* Summary According to CLHS, #+begin_quote A default initial value form for a slot is defined by using the :initform slot option to defclass. If no initialization argument associated with that slot is given as an argument to make-instance or is defaulted by :default-initargs, this default initial value form is evaluated in the lexical environment of the defclass form that defined it, and the resulting value is stored in the slot. #+end_quote --- [[clhs::07_a.htm][Object Creation and Initialization]] This is not what happens in eieio. Rather, initform is evaluated even when initarg is present. * Emacs Lisp examples Define a class with a slot that has an initarg and an initform involving undefined function: #+begin_src emacs-lisp (defclass test-initform () ((test-slot :initarg :test-slot :initform (identity (non-existent))))) #+end_src Now, #+begin_src emacs-lisp :results code :wrap example emacs-lisp (condition-case err (make-instance 'test-initform :test-slot 0) (t err)) #+end_src #+RESULTS: #+begin_example emacs-lisp (void-function non-existent) #+end_example Even though initform should not be evaluated since initarg is provided. * Other references from CLHS #+begin_quote If the initialization argument has a value in the initialization argument list, the value is stored into the slot of the newly created object, overriding any :initform form associated with the slot. #+end_quote --- [[clhs::07_aa.htm][Initialization Arguments]] #+begin_quote An :initform form is used to initialize a slot only if no initialization argument associated with that slot is given as an argument to make-instance or is defaulted by :default-initargs. #+end_quote --- [[clhs::07_ac.htm][Defaulting of Initialization Arguments]] #+begin_quote If a slot has both an :initform form and an :initarg slot option, and the initialization argument is defaulted using :default-initargs or is supplied to make-instance, the captured :initform form is neither used nor evaluated. #+end_quote --- [[clhs::07_ad.htm][Rules for Initialization Arguments]] * Common Lisp examples Define a class in exactly the same way as in Emacs Lisp: #+begin_src lisp :results errors :wrap example lisp (defclass test-initform () ((test-slot :initarg :test-slot :initform (identity (non-existent))))) #+end_src #+RESULTS: #+begin_example lisp ; in: DEFCLASS TEST-INITFORM ; (NON-EXISTENT) ; ; caught STYLE-WARNING: ; undefined function: COMMON-LISP-USER::NON-EXISTENT ; ; compilation unit finished ; Undefined function: ; NON-EXISTENT ; caught 1 STYLE-WARNING condition #+end_example Appropriately, #+begin_src lisp :results value verbatim :wrap example lisp (ignore-errors (make-instance 'test-initform)) #+end_src #+RESULTS: #+begin_example lisp NIL # #+end_example But with initarg, there is no need to evaluate initform, and it is not evaluated: #+begin_src lisp :results value verbatim :wrap example lisp (make-instance 'test-initform :test-slot 0) #+end_src #+RESULTS: #+begin_example lisp # #+end_example * Notes ** Initializing to quoted initform Emacs 27 source claims: #+begin_quote Paul Landes said in an email: > CL evaluates it if it can, and otherwise, leaves it as > the quoted thing as you already have. This is by the > Sonya E. Keene book and other things I've look at on the > web. #+end_quote --- [[file:/usr/share/emacs/27.2/lisp/emacs-lisp/eieio.el::;; Paul Landes said in an email:][EIEIO on initform quoting]] And eieio does quote initform forms with cars being symbols that are not fbound: #+begin_src lisp :results none (defclass test-initform-quote () ((test-slot :initform (non-existent)))) #+end_src #+begin_src emacs-lisp :results code :wrap example emacs-lisp (slot-value (make-instance 'test-initform-quote) 'test-slot) #+end_src #+RESULTS: #+begin_example emacs-lisp (non-existent) #+end_example There is however no reference to Sonya E. Keene or anything else. Meanwhile, #+begin_src lisp :results errors :wrap example lisp (defclass test-initform-quote () ((test-slot :initform (non-existent)))) #+end_src #+RESULTS: #+begin_example lisp ; in: DEFCLASS TEST-INITFORM-QUOTE ; (NON-EXISTENT) ; ; caught STYLE-WARNING: ; undefined function: COMMON-LISP-USER::NON-EXISTENT ; ; compilation unit finished ; Undefined function: ; NON-EXISTENT ; caught 1 STYLE-WARNING condition #+end_example #+begin_src lisp :results value verbatim :wrap example emacs-lisp (ignore-errors (make-instance 'test-initform-quote)) #+end_src #+RESULTS: #+begin_example emacs-lisp NIL # #+end_example Also, when discussing interplay between initform and default-initargs, Sonya E. Keene mentions: #+begin_quote The value of an :initform is evaluated each time it is used to initialize a slot. #+end_quote --- Sonya E. Keene, Object Oriented Programming in Common Lisp: A Programmer's Guide. 9.3. Controlling Initialization With ~defclass~ Options similarly stated in CLHS, in “Macro DEFCLASS”. Emacs 28 source removes the claim but adds #+begin_quote FIXME: Historically, EIEIO used a heuristic to try and guess whether the initform is a form to be evaluated or just a constant. We use `eieio--eval-default-p' to see what the heuristic says and if it disagrees with normal evaluation then tweak the initform to make it fit and emit a warning accordingly. #+end_quote --- [[file:~/src/emacs/lisp/emacs-lisp/eieio.el::;; FIXME: Historically, EIEIO used a heuristic to try and guess][eieio in git]] which arguably makes matters even more confusing. There should be no such heuristic. * Patch We offer a patch for Emacs 28 (master) but we can't build Emacs 28 (the bug had been filed) so it's untested and “works for me”.