Function: eieio-defclass-internal
eieio-defclass-internal is a byte-compiled function defined in
eieio-core.el.gz.
Signature
(eieio-defclass-internal CNAME SUPERCLASSES SLOTS OPTIONS)
Documentation
Define CNAME as a new subclass of SUPERCLASSES.
SLOTS are the slots residing in that class definition, and OPTIONS
holds the class options.
See defclass for more information.
This function has :after advice: eieio-defclass-internal@closql-object.
Source Code
;; Defined in /usr/src/emacs/lisp/emacs-lisp/eieio-core.el.gz
(defun eieio-defclass-internal (cname superclasses slots options)
"Define CNAME as a new subclass of SUPERCLASSES.
SLOTS are the slots residing in that class definition, and OPTIONS
holds the class options.
See `defclass' for more information."
;; Run our eieio-hook each time, and clear it when we are done.
;; This way people can add hooks safely if they want to modify eieio
;; or add definitions when eieio is loaded or something like that.
(run-hooks 'eieio-hook)
(setq eieio-hook nil)
(let* ((oldc (let ((c (cl--find-class cname))) (if (eieio--class-p c) c)))
(newc (or oldc
;; Reuse `oldc' instead of creating a new one, so that
;; existing references stay valid. E.g. when
;; reloading the file that does the `defclass', we don't
;; want to create a new class object.
(eieio--class-make cname)))
(groups nil)) ;; list of groups id'd from slots
;; If this class already existed, and we are updating its structure,
;; make sure we keep the old child list. This can cause bugs, but
;; if no new slots are created, it also saves time, and prevents
;; method table breakage, particularly when the users is only
;; byte compiling an EIEIO file.
(if oldc
(progn
(cl-assert (eq newc oldc))
;; Reset the fields.
(setf (eieio--class-parents newc) nil)
(setf (eieio--class-slots newc) nil)
(setf (eieio--class-initarg-tuples newc) nil)
(setf (eieio--class-class-slots newc) nil))
;; If the old class did not exist, but did exist in the autoload map,
;; then adopt those children. This is like the above, but deals with
;; autoloads nicely.
(let ((children (gethash cname eieio-defclass-autoload-map)))
(when children
(setf (eieio--class-children newc) children)
(remhash cname eieio-defclass-autoload-map))))
(unless (or superclasses (eq cname 'eieio-default-superclass))
(setq superclasses '(eieio-default-superclass)))
(if superclasses
(progn
(dolist (p superclasses)
(if (not (and p (symbolp p)))
(error "Invalid parent class %S" p)
(let ((c (cl--find-class p)))
(if (not (eieio--class-p c))
;; bad class
(error "Given parent class %S is not a class" p)
;; good parent class...
;; save new child in parent
(cl-pushnew cname (eieio--class-children c))
;; Get custom groups, and store them into our local copy.
(mapc (lambda (g) (cl-pushnew g groups :test #'equal))
(eieio--class-option c :custom-groups))
;; Save parent in child.
(push c (eieio--class-parents newc))))))
;; Reverse the list of our parents so that they are prioritized in
;; the same order as specified in the code.
(cl-callf nreverse (eieio--class-parents newc))
;; Before adding new slots, let's add all the methods and classes
;; in from the parent class.
(eieio-copy-parents-into-subclass newc))
(cl-assert (eq cname 'eieio-default-superclass))
(setf (eieio--class-parents newc) (list (cl--find-class 'record))))
;; turn this into a usable self-pointing symbol; FIXME: Why?
(when eieio-backward-compatibility
(set cname cname)
(make-obsolete-variable cname (format "use '%s instead" cname)
"25.1"))
;; Store the new class vector definition into the symbol. We need to
;; do this first so that we can call defmethod for the accessor.
;; The vector will be updated by the following while loop and will not
;; need to be stored a second time.
(setf (cl--find-class cname) newc)
;; Query each slot in the declaration list and mangle into the
;; class structure I have defined.
(pcase-dolist (`(,name . ,slot) slots)
(let* ((init (or (plist-get slot :initform)
(if (member :initform slot) nil
eieio--unbound-form)))
(initarg (plist-get slot :initarg))
(docstr (plist-get slot :documentation))
(prot (plist-get slot :protection))
(alloc (plist-get slot :allocation))
(type (plist-get slot :type))
(custom (plist-get slot :custom))
(label (plist-get slot :label))
(customg (plist-get slot :group))
(printer (plist-get slot :printer))
(skip-nil (eieio--class-option-assoc options :allow-nil-initform))
)
(unless (or (macroexp-const-p init)
(eieio--eval-default-p init))
;; FIXME: We duplicate this test here and in `defclass' because
;; if we move this part to `defclass' we may break some existing
;; code (because the `fboundp' test in `eieio--eval-default-p'
;; returns a different result at compile time).
(setq init (macroexp-quote init)))
;; Clean up the meaning of protection.
(setq prot
(pcase prot
((or 'nil 'public :public) nil)
((or 'protected :protected) 'protected)
((or 'private :private) 'private)
(_ (signal 'invalid-slot-type (list :protection prot)))))
;; The default type specifier is supposed to be t, meaning anything.
(if (not type) (setq type t))
;; intern the symbol so we can use it blankly
(if eieio-backward-compatibility
(and initarg (not (keywordp initarg))
(progn
(set initarg initarg)
(make-obsolete-variable
initarg (format "use '%s instead" initarg) "25.1"))))
;; The customgroup should be a list of symbols.
(cond ((and (null customg) custom)
(setq customg '(default)))
((not (listp customg))
(setq customg (list customg))))
;; The customgroup better be a list of symbols.
(dolist (cg customg)
(unless (symbolp cg)
(signal 'invalid-slot-type (list :group cg))))
;; First up, add this slot into our new class.
(eieio--add-new-slot
newc (cl--make-slot-descriptor
name init type
`(,@(if docstr `((:documentation . ,docstr)))
,@(if custom `((:custom . ,custom)))
,@(if label `((:label . ,label)))
,@(if customg `((:group . ,customg)))
,@(if printer `((:printer . ,printer)))
,@(if prot `((:protection . ,prot)))))
initarg alloc 'defaultoverride skip-nil)
;; We need to id the group, and store them in a group list attribute.
(dolist (cg customg)
(cl-pushnew cg groups :test #'equal))
))
;; Now that everything has been loaded up, all our lists are backwards!
;; Fix that up now and turn them into vectors.
(cl-callf (lambda (slots) (apply #'vector (nreverse slots)))
(eieio--class-slots newc))
(cl-callf nreverse (eieio--class-initarg-tuples newc))
;; The storage for class-class-allocation-type needs to be turned into
;; a vector now.
(cl-callf (lambda (slots) (apply #'vector slots))
(eieio--class-class-slots newc))
;; Also, setup the class allocated values.
(let* ((slots (eieio--class-class-slots newc))
(n (length slots))
(v (make-vector n nil)))
(dotimes (i n)
(setf (aref v i) (eval
(cl--slot-descriptor-initform (aref slots i))
t)))
(setf (eieio--class-class-allocation-values newc) v))
;; Attach slot symbols into a hash table, and store the index of
;; this slot as the value this table.
(let* ((slots (eieio--class-slots newc))
;; (cslots (eieio--class-class-slots newc))
(oa (make-hash-table :test #'eq)))
;; (dotimes (cnt (length cslots))
;; (setf (gethash (cl--slot-descriptor-name (aref cslots cnt)) oa) (- -1 cnt)))
(dotimes (cnt (length slots))
(setf (gethash (cl--slot-descriptor-name (aref slots cnt)) oa)
(+ (eval-when-compile eieio--object-num-slots) cnt)))
(setf (eieio--class-index-table newc) oa))
;; Set up a specialized doc string.
;; Use stored value since it is calculated in a non-trivial way
(let ((docstring (eieio--class-option-assoc options :documentation)))
(setf (eieio--class-docstring newc) docstring)
(when eieio-backward-compatibility
(put cname 'variable-documentation docstring)))
;; Save the file location where this class is defined.
(add-to-list 'current-load-list `(define-type . ,cname))
;; We have a list of custom groups. Store them into the options.
(let ((g (eieio--class-option-assoc options :custom-groups)))
(mapc (lambda (cg) (cl-pushnew cg g :test 'equal)) groups)
(if (memq :custom-groups options)
(setcar (cdr (memq :custom-groups options)) g)
(setq options (cons :custom-groups (cons g options)))))
;; Set up the options we have collected.
(setf (eieio--class-options newc) options)
;; Create the cached default object.
(let ((cache (make-record newc
(+ (length (eieio--class-slots newc))
;; FIXME: Why +1 -1 ?
(eval-when-compile eieio--object-num-slots)
-1)
nil)))
(let ((eieio-skip-typecheck t))
;; All type-checking has been done to our satisfaction
;; before this call. Don't waste our time in this call..
(eieio-set-defaults cache t))
(setf (eieio--class-default-object-cache newc) cache))
;; Return our new class object
;; newc
cname
))