GNU bug report logs -
#77464
X is already defined as something else than a generic function
Previous Next
To reply to this bug, email your comments to 77464 AT debbugs.gnu.org.
Toggle the display of automated, internal messages from the tracker.
Report forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#77464
; Package
emacs
.
(Wed, 02 Apr 2025 16:01:02 GMT)
Full text and
rfc822 format available.
Acknowledgement sent
to
Jonas Bernoulli <jonas <at> bernoul.li>
:
New bug report received and forwarded. Copy sent to
bug-gnu-emacs <at> gnu.org
.
(Wed, 02 Apr 2025 16:01:02 GMT)
Full text and
rfc822 format available.
Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
Hello,
Users of my packages occasionally report such errors but I was never
able to reproduce. What is strange is that X always was a function that
was definitely not defined as "something else than a generic function"
anywhere in my code, or even just in past versions of my code, and users
were not able to find anything in their configuration or third-party
packages either.
Actually I have seen this issue myself a few times, but it was always
when I badly messed up something else and by the time I had fixed that,
the "something other" issue was also gone. In hindsight it is obvious
that I should sooner have investigated the "something other" issue
without first fixing the seemingly unrelated issue.
Now that I have finally done that, I also managed to come of with a
reproducer.
1. Create a file "demo.el" with contents:
(require 'eieio)
(defclass demo-class () ())
(cl-defmethod demo-function ((obj demo-class)) obj)
(error "something else goes wrong here")
(provide 'demo)
2. Optionally apply this patch to Emacs:
diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el
@@ -193,8 +193,8 @@ cl-generic-ensure-function
(autoloadp (symbol-function name))
(and (functionp name) generic)
noerror)
- (error "%s is already defined as something else than a generic function"
- origname))
+ (error "%s [%s] is already defined as something else than a generic function"
+ origname (symbol-function name)))
(if generic
(cl-assert (eq name (cl--generic-name generic)))
(setf (cl--generic name) (setq generic (cl--generic-make name))))
@@ -645,7 +645,9 @@ cl-generic-define-method
;; is still valid (e.g. still empty method cache)?
(gfun (cl--generic-make-function generic)))
(unless (symbol-function sym)
- (defalias sym 'dummy)) ;Record definition into load-history.
+ (defalias sym 'dummy) ;Record definition into load-history.
+ (when (eq sym 'demo-function)
+ (message "First defalias: %s" (symbol-function 'demo-function))))
(cl-pushnew `(cl-defmethod . ,(cl--generic-load-hist-format
(cl--generic-name generic)
qualifiers specializers))
@@ -659,7 +661,9 @@ cl-generic-define-method
(set-advertised-calling-convention gfun old-adv-cc nil))
;; But do use `defalias', so that it interacts properly with nadvice,
;; e.g. for tracing/debug-on-entry.
- (defalias sym gfun)))))
+ (defalias sym gfun)
+ (when (eq sym 'demo-function)
+ (message "Second defalias: %s" (symbol-function 'demo-function)))))))
(defvar cl--generic-dispatchers (make-hash-table :test #'equal))
3. Paste this into a buffer and adjust the load-path:
(add-to-list 'load-path "/path/to/demo")
(message "Load attempt one... [%s]" (symbol-function 'demo-function))
(with-demoted-errors "Trigger: %S"
(require 'demo))
(message "Load attempt one...done")
(message "Load attempt two... [%s]" (symbol-function 'demo-function))
(require 'demo)
(message "Load attempt two...done")
4. Evaluate that buffer, you'll get this output:
Load attempt one... [nil]
First defalias: dummy
Second defalias: #[...]
Trigger: (error "something else goes wrong here")
Load attempt one...done
Load attempt two... [dummy]
cl-generic-ensure-function: demo-function [dummy] is already defined \
as something else than a generic function
cl-generic-define-method first sets (symbol-function 'demo-function)
to 'dummy, and then it successfully sets it to something else. The
debug statements helped confirm that both defalias calls are actually
successful, i.e., the problem isn't that something in between these
calls ends up calling cl-generic-ensure-function.
Then, after this function has returned, something else goes wrong (in
this reproducer intentionally). We can then observe that the value of
(symbol-function 'demo-function) somehow goes back to being 'dummy.
(I couldn't find anything else in Emacs that sets a symbol-function to
'dummy.)
The first (require 'demo) failed because the (here intentional) error
occurred before the provide form was reached. Once a second attempt to
require the same library is made, the cl-defmethod fails because the
encountered 'dummy is "something else than a generic function".
(Also, isn't it "something OTHER than a generic function"?)
Cheers,
Jonas
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#77464
; Package
emacs
.
(Sun, 13 Apr 2025 08:19:04 GMT)
Full text and
rfc822 format available.
Message #8 received at 77464 <at> debbugs.gnu.org (full text, mbox):
> Date: Wed, 02 Apr 2025 17:59:53 +0200
> From: Jonas Bernoulli via "Bug reports for GNU Emacs,
> the Swiss army knife of text editors" <bug-gnu-emacs <at> gnu.org>
>
> Hello,
>
> Users of my packages occasionally report such errors but I was never
> able to reproduce. What is strange is that X always was a function that
> was definitely not defined as "something else than a generic function"
> anywhere in my code, or even just in past versions of my code, and users
> were not able to find anything in their configuration or third-party
> packages either.
>
> Actually I have seen this issue myself a few times, but it was always
> when I badly messed up something else and by the time I had fixed that,
> the "something other" issue was also gone. In hindsight it is obvious
> that I should sooner have investigated the "something other" issue
> without first fixing the seemingly unrelated issue.
>
> Now that I have finally done that, I also managed to come of with a
> reproducer.
>
> 1. Create a file "demo.el" with contents:
>
> (require 'eieio)
> (defclass demo-class () ())
> (cl-defmethod demo-function ((obj demo-class)) obj)
>
> (error "something else goes wrong here")
> (provide 'demo)
>
> 2. Optionally apply this patch to Emacs:
>
> diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el
> @@ -193,8 +193,8 @@ cl-generic-ensure-function
> (autoloadp (symbol-function name))
> (and (functionp name) generic)
> noerror)
> - (error "%s is already defined as something else than a generic function"
> - origname))
> + (error "%s [%s] is already defined as something else than a generic function"
> + origname (symbol-function name)))
> (if generic
> (cl-assert (eq name (cl--generic-name generic)))
> (setf (cl--generic name) (setq generic (cl--generic-make name))))
> @@ -645,7 +645,9 @@ cl-generic-define-method
> ;; is still valid (e.g. still empty method cache)?
> (gfun (cl--generic-make-function generic)))
> (unless (symbol-function sym)
> - (defalias sym 'dummy)) ;Record definition into load-history.
> + (defalias sym 'dummy) ;Record definition into load-history.
> + (when (eq sym 'demo-function)
> + (message "First defalias: %s" (symbol-function 'demo-function))))
> (cl-pushnew `(cl-defmethod . ,(cl--generic-load-hist-format
> (cl--generic-name generic)
> qualifiers specializers))
> @@ -659,7 +661,9 @@ cl-generic-define-method
> (set-advertised-calling-convention gfun old-adv-cc nil))
> ;; But do use `defalias', so that it interacts properly with nadvice,
> ;; e.g. for tracing/debug-on-entry.
> - (defalias sym gfun)))))
> + (defalias sym gfun)
> + (when (eq sym 'demo-function)
> + (message "Second defalias: %s" (symbol-function 'demo-function)))))))
>
> (defvar cl--generic-dispatchers (make-hash-table :test #'equal))
>
> 3. Paste this into a buffer and adjust the load-path:
>
> (add-to-list 'load-path "/path/to/demo")
>
> (message "Load attempt one... [%s]" (symbol-function 'demo-function))
> (with-demoted-errors "Trigger: %S"
> (require 'demo))
> (message "Load attempt one...done")
> (message "Load attempt two... [%s]" (symbol-function 'demo-function))
> (require 'demo)
> (message "Load attempt two...done")
>
> 4. Evaluate that buffer, you'll get this output:
>
> Load attempt one... [nil]
> First defalias: dummy
> Second defalias: #[...]
> Trigger: (error "something else goes wrong here")
> Load attempt one...done
> Load attempt two... [dummy]
> cl-generic-ensure-function: demo-function [dummy] is already defined \
> as something else than a generic function
>
>
> cl-generic-define-method first sets (symbol-function 'demo-function)
> to 'dummy, and then it successfully sets it to something else. The
> debug statements helped confirm that both defalias calls are actually
> successful, i.e., the problem isn't that something in between these
> calls ends up calling cl-generic-ensure-function.
>
> Then, after this function has returned, something else goes wrong (in
> this reproducer intentionally). We can then observe that the value of
> (symbol-function 'demo-function) somehow goes back to being 'dummy.
> (I couldn't find anything else in Emacs that sets a symbol-function to
> 'dummy.)
>
> The first (require 'demo) failed because the (here intentional) error
> occurred before the provide form was reached. Once a second attempt to
> require the same library is made, the cl-defmethod fails because the
> encountered 'dummy is "something else than a generic function".
>
> (Also, isn't it "something OTHER than a generic function"?)
Stefan, any comments or suggestions?
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#77464
; Package
emacs
.
(Sun, 13 Apr 2025 16:52:02 GMT)
Full text and
rfc822 format available.
Message #11 received at 77464 <at> debbugs.gnu.org (full text, mbox):
Hi Jonas,
>> Now that I have finally done that, I also managed to come of with a
>> reproducer.
>>
>> 1. Create a file "demo.el" with contents:
>>
>> (require 'eieio)
>> (defclass demo-class () ())
>> (cl-defmethod demo-function ((obj demo-class)) obj)
>>
>> (error "something else goes wrong here")
>> (provide 'demo)
I pushed to `master` what I think should fix this problem.
Can you try again?
Stefan
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#77464
; Package
emacs
.
(Mon, 14 Apr 2025 18:15:01 GMT)
Full text and
rfc822 format available.
Message #14 received at 77464 <at> debbugs.gnu.org (full text, mbox):
Hello Stefan
Stefan Monnier <monnier <at> iro.umontreal.ca> writes:
>>> Now that I have finally done that, I also managed to come of with a
>>> reproducer.
>>>
>>> 1. Create a file "demo.el" with contents:
>>>
>>> (require 'eieio)
>>> (defclass demo-class () ())
>>> (cl-defmethod demo-function ((obj demo-class)) obj)
>>>
>>> (error "something else goes wrong here")
>>> (provide 'demo)
>
> I pushed to `master` what I think should fix this problem.
> Can you try again?
That fixed the issue. It's now also easier to understand why, when and
how this avoids recording the location.
Of course that won't fix the issue for released Emacsen, and for anyone
who runs into this and has not seen this thread that continues to be
very confusing. Can you think of any workaround beside making sure that
each and every generic function is first declared using cl-defgeneric?
>> Then, after this function has returned, something else goes wrong (in
>> this reproducer intentionally). We can then observe that the value of
>> (symbol-function 'demo-function) somehow goes back to being 'dummy.
>> (I couldn't find anything else in Emacs that sets a symbol-function to
>> 'dummy.)
Could you please explain what was happening? To me this still looks
like the value somehow magically goes back to 'dummy.
Thanks!
Jonas
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#77464
; Package
emacs
.
(Tue, 15 Apr 2025 14:05:01 GMT)
Full text and
rfc822 format available.
Message #17 received at 77464 <at> debbugs.gnu.org (full text, mbox):
> Of course that won't fix the issue for released Emacsen, and for anyone
> who runs into this and has not seen this thread that continues to be
> very confusing. Can you think of any workaround beside making sure that
> each and every generic function is first declared using cl-defgeneric?
Don't signal an error while loading a file?
>>> Then, after this function has returned, something else goes wrong (in
>>> this reproducer intentionally). We can then observe that the value of
>>> (symbol-function 'demo-function) somehow goes back to being 'dummy.
>>> (I couldn't find anything else in Emacs that sets a symbol-function to
>>> 'dummy.)
> Could you please explain what was happening? To me this still looks
> like the value somehow magically goes back to 'dummy.
I have not worked out the details of the sequence of events, to be honest.
AFAICT, the "magic" comes from the code that tries to undo partial loads
when an error is encountered in the middle of loading a file (which
involves the `function-history` symbol property and the `Vautoload_queue`).
It's quite possible that it's a result of a bug in there.
Stefan
This bug report was last modified 18 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.