From 4c6554413d318069239ba83f4f42fa2452801d30 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Sat, 12 Jun 2021 16:22:03 -0400 Subject: EIEIO: Promote the CLOS behavior over the EIEIO-specific behavior Change docs to advertize `slot-value` rather than `oref`. Change the implementation of `:initform` to better match the CLOS semantics, while preserving the EIEIO semantics, but warn when encountering cases where the two diverge. Demote the mostly unused special semantics of `oref-default` on non-class allocated slots. * doc/misc/eieio.texi (Quick Start): Use `slot-value`. (Accessing Slots): Move `slot-value` before `oref`. Fix paren-typo in example (reported by pillule ). (Introspection): Remove mention of `class-slot-initarg`. * lisp/transient.el (transient--parse-group, transient--parse-suffix): Don't use `oref-default` to get the default value. (transient-lisp-variable): Init forms are evaluated. * lisp/emacs-lisp/eieio.el (defclass): Warn about inapplicable `:initarg` and about uses of init forms that are ambiguous. (oref): Don't advertize the deprecated use of initargs as slot names. (oref-default): Don't advertize the deprecated case where it returns the initform's value. (initialize-instance): Use `macroexp-const-p`. * lisp/emacs-lisp/eieio-core.el (eieio--unbound): Rename from `eieio-unbound`. (eieio--unbound-form): New var. (eieio--slot-override): Use it. (eieio-defclass-internal): Use it. Change `init` so it should always be evaluated. (eieio--known-class-slot-names): New var. (eieio--eval-default-p): Rename from `eieio-eval-default-p`. (eieio--perform-slot-validation-for-default): Use `macroexp-const-p` to decide whether to skip the test. (eieio--add-new-slot): Register slot in `eieio--known-class-slot-names` when applicable. (eieio-oref-default, eieio-oset-default): Add warning for unknown slots and slots not known to be allocated to the class. (eieio-default-eval-maybe): Delete function. Use just `eval` instead. (eieio-declare-slots): Allow slots to specify their allocation class. * lisp/cedet/srecode/insert.el (point): Declare the slot instead of moving the class definition before the slot's first use. (srecode-template-inserter-point, srecode-insert-fcn): Use nil instead of unbound for the `point` slot. * lisp/cedet/srecode/compile.el (srecode-template-inserter): Declare the `key` slot that all children should have. * lisp/emacs-lisp/eieio-speedbar.el (eieio-speedbar) (eieio-speedbar-directory-button, eieio-speedbar-file-button): * lisp/emacs-lisp/eieio-custom.el (eieio-widget-test-class): * lisp/emacs-lisp/chart.el (chart-bar): * lisp/cedet/semantic/ede-grammar.el (semantic-ede-proj-target-grammar): * lisp/cedet/semantic/db.el (semanticdb-project-database): * lisp/cedet/semantic/db-javascript.el (semanticdb-table-javascript) (semanticdb-project-database-javascript): * lisp/cedet/semantic/db-el.el (semanticdb-table-emacs-lisp) (semanticdb-project-database-emacs-lisp): * lisp/cedet/semantic/db-ebrowse.el (semanticdb-table-ebrowse) (semanticdb-project-database-ebrowse): * lisp/cedet/ede/proj.el (ede-proj-project): * lisp/cedet/ede/proj-obj.el (ede-proj-target-makefile-objectcode): * lisp/cedet/ede/generic.el (ede-generic-project): * lisp/cedet/ede/config.el (ede-project-with-config): * lisp/cedet/ede/base.el (ede-target, ede-project): * lisp/auth-source.el (auth-source-backend): Init forms are evaluated, so quote them accordingly. --- lisp/emacs-lisp/eieio.el | 57 +++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 23 deletions(-) (limited to 'lisp/emacs-lisp/eieio.el') diff --git a/lisp/emacs-lisp/eieio.el b/lisp/emacs-lisp/eieio.el index 31b6b0945bb..1c8c372aaef 100644 --- a/lisp/emacs-lisp/eieio.el +++ b/lisp/emacs-lisp/eieio.el @@ -131,6 +131,7 @@ and reference them using the function `class-option'." (let ((testsym1 (intern (concat (symbol-name name) "-p"))) (testsym2 (intern (format "%s--eieio-childp" name))) + (warnings '()) (accessors ())) ;; Collect the accessors we need to define. @@ -145,6 +146,8 @@ and reference them using the function `class-option'." ;; Update eieio--known-slot-names already in case we compile code which ;; uses this before the class is loaded. (cl-pushnew sname eieio--known-slot-names) + (when (eq alloc :class) + (cl-pushnew sname eieio--known-class-slot-names)) (if eieio-error-unsupported-class-tags (let ((tmp soptions)) @@ -176,8 +179,22 @@ and reference them using the function `class-option'." (signal 'invalid-slot-type (list :label label))) ;; Is there an initarg, but allocation of class? - (if (and initarg (eq alloc :class)) - (message "Class allocated slots do not need :initarg")) + (when (and initarg (eq alloc :class)) + (push (format "Meaningless :initarg for class allocated slot '%S'" + sname) + warnings)) + + (let ((init (plist-get soptions :initform))) + (unless (or (macroexp-const-p init) + (eieio--eval-default-p init)) + ;; 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. + (push (format "Ambiguous initform needs quoting: %S" init) + warnings))) ;; Anyone can have an accessor function. This creates a function ;; of the specified name, and also performs a `defsetf' if applicable @@ -223,6 +240,8 @@ This method is obsolete." )) `(progn + ,@(mapcar (lambda (w) (macroexp-warn-and-return w `(progn ',w) 'compile-only)) + warnings) ;; This test must be created right away so we can have self- ;; referencing classes. ei, a class whose slot can contain only ;; pointers to itself. @@ -282,9 +301,7 @@ This method is obsolete." ;;; Get/Set slots in an object. ;; (defmacro oref (obj slot) - "Retrieve the value stored in OBJ in the slot named by SLOT. -Slot is the name of the slot when created by `defclass' or the label -created by the :initarg tag." + "Retrieve the value stored in OBJ in the slot named by SLOT." (declare (debug (form symbolp))) `(eieio-oref ,obj (quote ,slot))) @@ -292,13 +309,11 @@ created by the :initarg tag." (defalias 'set-slot-value #'eieio-oset) (make-obsolete 'set-slot-value "use (setf (slot-value ..) ..) instead" "25.1") -(defmacro oref-default (obj slot) - "Get the default value of OBJ (maybe a class) for SLOT. -The default value is the value installed in a class with the :initform -tag. SLOT can be the slot name, or the tag specified by the :initarg -tag in the `defclass' call." +(defmacro oref-default (class slot) + "Get the value of class allocated slot SLOT. +CLASS can also be an object, in which case we use the object's class." (declare (debug (form symbolp))) - `(eieio-oref-default ,obj (quote ,slot))) + `(eieio-oref-default ,class (quote ,slot))) ;;; Handy CLOS macros ;; @@ -538,11 +553,11 @@ OBJECT can be an instance or a class." ((eieio-object-p object) (eieio-oref object slot)) ((symbolp object) (eieio-oref-default object slot)) (t (signal 'wrong-type-argument (list 'eieio-object-p object)))) - eieio-unbound)))) + eieio--unbound)))) (defun slot-makeunbound (object slot) "In OBJECT, make SLOT unbound." - (eieio-oset object slot eieio-unbound)) + (eieio-oset object slot eieio--unbound)) (defun slot-exists-p (object-or-class slot) "Return non-nil if OBJECT-OR-CLASS has SLOT." @@ -740,18 +755,14 @@ dynamically set from SLOTS." (slots (eieio--class-slots this-class))) (dotimes (i (length slots)) ;; For each slot, see if we need to evaluate it. - ;; - ;; 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. (let* ((slot (aref slots i)) - (initform (cl--slot-descriptor-initform slot)) - (dflt (eieio-default-eval-maybe initform))) - (when (not (eq dflt initform)) + (initform (cl--slot-descriptor-initform slot))) + ;; Those slots whose initform is constant already have the right + ;; value set in the default-object. + (unless (macroexp-const-p initform) ;; FIXME: We should be able to just do (aset this (+ i ) dflt)! - (eieio-oset this (cl--slot-descriptor-name slot) dflt))))) + (eieio-oset this (cl--slot-descriptor-name slot) + (eval initform t)))))) ;; Shared initialize will parse our slots for us. (shared-initialize this slots)) -- cgit v1.2.3