Package: emacs;
Reported by: Jonas Bernoulli <jonas <at> bernoul.li>
Date: Wed, 2 Apr 2025 16:01:01 UTC
Severity: normal
View this message in rfc822 format
From: Jonas Bernoulli <jonas <at> bernoul.li> To: 77464 <at> debbugs.gnu.org Subject: bug#77464: X is already defined as something else than a generic function Date: Wed, 02 Apr 2025 17:59:53 +0200
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
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.