aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2015-01-08 15:47:32 -0500
committerStefan Monnier2015-01-08 15:47:32 -0500
commit6a67b20ddd458d71a1d63746504d91b1acea9b2b (patch)
tree38ff716a76899e0638246d28d6a465b8dcf50522
parent54181569d255322bdae321dc3fddeb465780fbe0 (diff)
downloademacs-6a67b20ddd458d71a1d63746504d91b1acea9b2b.tar.gz
emacs-6a67b20ddd458d71a1d63746504d91b1acea9b2b.zip
* lisp/emacs-lisp/eieio*.el: Move the function defs to defclass.
* lisp/emacs-lisp/eieio.el (defclass): Move from eieio-defclass all the code that creates functions, and most of the sanity checks. Mark as obsolete the <class>-child-p function. * lisp/emacs-lisp/eieio-core.el (eieio--define-field-accessors): Remove. (eieio--class, eieio--object): Use cl-defstruct. (eieio--object-num-slots): Define manually. (eieio-defclass-autoload): Use eieio--class-make. (eieio-defclass-internal): Rename from eieio-defclass. Move all the `(lambda...) definitions and most of the sanity checks to `defclass'. Mark as obsolete the <class>-list-p function, the <class> variable and the <initarg> variables. Use pcase-dolist. (eieio-defclass): New compatibility function. * lisp/emacs-lisp/eieio-opt.el (eieio-build-class-alist) (eieio-class-speedbar): Don't use eieio-default-superclass var.
-rw-r--r--etc/NEWS7
-rw-r--r--lisp/ChangeLog18
-rw-r--r--lisp/emacs-lisp/eieio-core.el358
-rw-r--r--lisp/emacs-lisp/eieio-opt.el4
-rw-r--r--lisp/emacs-lisp/eieio.el186
5 files changed, 301 insertions, 272 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 14a91768680..0f20be86b9b 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1,6 +1,6 @@
1GNU Emacs NEWS -- history of user-visible changes. 1GNU Emacs NEWS -- history of user-visible changes.
2 2
3Copyright (C) 2014 Free Software Foundation, Inc. 3Copyright (C) 2014, 2015 Free Software Foundation, Inc.
4See the end of the file for license conditions. 4See the end of the file for license conditions.
5 5
6Please send Emacs bug reports to bug-gnu-emacs@gnu.org. 6Please send Emacs bug reports to bug-gnu-emacs@gnu.org.
@@ -187,6 +187,11 @@ Unicode standards.
187 187
188 188
189* Changes in Specialized Modes and Packages in Emacs 25.1 189* Changes in Specialized Modes and Packages in Emacs 25.1
190
191** EIEIO
192*** The <class>-list-p and <class>-child-p functions are declared obsolete.
193*** The <class> variables are declared obsolete.
194*** The <initarg> variables are declared obsolete.
190** ido 195** ido
191*** New command `ido-bury-buffer-at-head' bound to C-S-b 196*** New command `ido-bury-buffer-at-head' bound to C-S-b
192Bury the buffer at the head of `ido-matches', analogous to how C-k 197Bury the buffer at the head of `ido-matches', analogous to how C-k
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 66b3b8eb061..6d7bfae31ce 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,9 +1,27 @@
12015-01-08 Stefan Monnier <monnier@iro.umontreal.ca> 12015-01-08 Stefan Monnier <monnier@iro.umontreal.ca>
2 2
3 * emacs-lisp/eieio.el (defclass): Move from eieio-defclass all the code
4 that creates functions, and most of the sanity checks.
5 Mark as obsolete the <class>-child-p function.
6 * emacs-lisp/eieio-core.el (eieio--define-field-accessors): Remove.
7 (eieio--class, eieio--object): Use cl-defstruct.
8 (eieio--object-num-slots): Define manually.
9 (eieio-defclass-autoload): Use eieio--class-make.
10 (eieio-defclass-internal): Rename from eieio-defclass. Move all the
11 `(lambda...) definitions and most of the sanity checks to `defclass'.
12 Mark as obsolete the <class>-list-p function, the <class> variable and
13 the <initarg> variables. Use pcase-dolist.
14 (eieio-defclass): New compatibility function.
15 * emacs-lisp/eieio-opt.el (eieio-build-class-alist)
16 (eieio-class-speedbar): Don't use eieio-default-superclass var.
17
182015-01-08 Stefan Monnier <monnier@iro.umontreal.ca>
19
3 * emacs-lisp/eieio-generic.el: New file. 20 * emacs-lisp/eieio-generic.el: New file.
4 * emacs-lisp/eieio-core.el: Move all generic function code to 21 * emacs-lisp/eieio-core.el: Move all generic function code to
5 eieio-generic.el. 22 eieio-generic.el.
6 (eieio--defmethod): Declare. 23 (eieio--defmethod): Declare.
24
7 * emacs-lisp/eieio.el: Require eieio-generic. Move all generic 25 * emacs-lisp/eieio.el: Require eieio-generic. Move all generic
8 function code to eieio-generic.el. 26 function code to eieio-generic.el.
9 * emacs-lisp/eieio-opt.el (eieio-help-generic): Move to 27 * emacs-lisp/eieio-opt.el (eieio-help-generic): Move to
diff --git a/lisp/emacs-lisp/eieio-core.el b/lisp/emacs-lisp/eieio-core.el
index fba4d8f50c7..dc2c873eb42 100644
--- a/lisp/emacs-lisp/eieio-core.el
+++ b/lisp/emacs-lisp/eieio-core.el
@@ -32,6 +32,7 @@
32;;; Code: 32;;; Code:
33 33
34(require 'cl-lib) 34(require 'cl-lib)
35(require 'pcase)
35 36
36(put 'eieio--defalias 'byte-hunk-handler 37(put 'eieio--defalias 'byte-hunk-handler
37 #'byte-compile-file-form-defalias) ;;(get 'defalias 'byte-hunk-handler) 38 #'byte-compile-file-form-defalias) ;;(get 'defalias 'byte-hunk-handler)
@@ -117,66 +118,70 @@ Currently under control of this var:
117 `(let ((eieio--scoped-class-stack (cons ,class eieio--scoped-class-stack))) 118 `(let ((eieio--scoped-class-stack (cons ,class eieio--scoped-class-stack)))
118 ,@forms)) 119 ,@forms))
119 120
120;;; 121(progn
121;; Field Accessors 122 ;; Arrange for field access not to bother checking if the access is indeed
122;; 123 ;; made to an eieio--class object.
123(defmacro eieio--define-field-accessors (prefix fields) 124 (cl-declaim (optimize (safety 0)))
124 (declare (indent 1)) 125(cl-defstruct (eieio--class
125 (let ((index 0) 126 (:constructor nil)
126 (defs '())) 127 (:constructor eieio--class-make (symbol &aux (tag 'defclass)))
127 (dolist (field fields) 128 (:type vector)
128 (let ((doc (if (listp field) 129 (:copier nil))
129 (prog1 (cadr field) (setq field (car field)))))) 130 ;; We use an untagged cl-struct, with our own hand-made tag as first field
130 (push `(defmacro ,(intern (format "eieio--%s-%s" prefix field)) (x) 131 ;; (containing the symbol `defclass'). It would be better to use a normal
131 ,@(if doc (list (format (if (string-match "\n" doc) 132 ;; cl-struct with its normal tag (e.g. so that cl-defstruct can define the
132 "Return %s" "Return %s of a %s.") 133 ;; predicate for us), but that breaks compatibility with .elc files compiled
133 doc prefix))) 134 ;; against older versions of EIEIO.
134 (list 'aref x ,index)) 135 tag
135 defs) 136 symbol ;; symbol (self-referencing)
136 (setq index (1+ index)))) 137 parent children
137 `(eval-and-compile 138 symbol-hashtable ;; hashtable permitting fast access to variable position indexes
138 ,@(nreverse defs) 139 ;; @todo
139 (defconst ,(intern (format "eieio--%s-num-slots" prefix)) ,index)))) 140 ;; the word "public" here is leftovers from the very first version.
140 141 ;; Get rid of it!
141(eieio--define-field-accessors class 142 public-a ;; class attribute index
142 (-unused-0 ;;Constant slot, set to `defclass'. 143 public-d ;; class attribute defaults index
143 (symbol "symbol (self-referencing)") 144 public-doc ;; class documentation strings for attributes
144 parent children 145 public-type ;; class type for a slot
145 (symbol-hashtable "hashtable permitting fast access to variable position indexes") 146 public-custom ;; class custom type for a slot
146 ;; @todo 147 public-custom-label ;; class custom group for a slot
147 ;; the word "public" here is leftovers from the very first version. 148 public-custom-group ;; class custom group for a slot
148 ;; Get rid of it! 149 public-printer ;; printer for a slot
149 (public-a "class attribute index") 150 protection ;; protection for a slot
150 (public-d "class attribute defaults index") 151 initarg-tuples ;; initarg tuples list
151 (public-doc "class documentation strings for attributes") 152 class-allocation-a ;; class allocated attributes
152 (public-type "class type for a slot") 153 class-allocation-doc ;; class allocated documentation
153 (public-custom "class custom type for a slot") 154 class-allocation-type ;; class allocated value type
154 (public-custom-label "class custom group for a slot") 155 class-allocation-custom ;; class allocated custom descriptor
155 (public-custom-group "class custom group for a slot") 156 class-allocation-custom-label ;; class allocated custom descriptor
156 (public-printer "printer for a slot") 157 class-allocation-custom-group ;; class allocated custom group
157 (protection "protection for a slot") 158 class-allocation-printer ;; class allocated printer for a slot
158 (initarg-tuples "initarg tuples list") 159 class-allocation-protection ;; class allocated protection list
159 (class-allocation-a "class allocated attributes") 160 class-allocation-values ;; class allocated value vector
160 (class-allocation-doc "class allocated documentation") 161 default-object-cache ;; what a newly created object would look like.
161 (class-allocation-type "class allocated value type") 162 ; This will speed up instantiation time as
162 (class-allocation-custom "class allocated custom descriptor") 163 ; only a `copy-sequence' will be needed, instead of
163 (class-allocation-custom-label "class allocated custom descriptor") 164 ; looping over all the values and setting them from
164 (class-allocation-custom-group "class allocated custom group") 165 ; the default.
165 (class-allocation-printer "class allocated printer for a slot") 166 options ;; storage location of tagged class option
166 (class-allocation-protection "class allocated protection list") 167 ; Stored outright without modifications or stripping
167 (class-allocation-values "class allocated value vector") 168 )
168 (default-object-cache "what a newly created object would look like. 169 ;; Set it back to the default value.
169This will speed up instantiation time as only a `copy-sequence' will 170 (cl-declaim (optimize (safety 1))))
170be needed, instead of looping over all the values and setting them 171
171from the default.") 172
172 (options "storage location of tagged class options. 173(cl-defstruct (eieio--object
173Stored outright without modifications or stripping."))) 174 (:type vector) ;We manage our own tagging system.
174 175 (:constructor nil)
175(eieio--define-field-accessors object 176 (:copier nil))
176 ;; `class-tag' holds a symbol, which is not the class name, but is instead 177 ;; `class-tag' holds a symbol, which is not the class name, but is instead
177 ;; properly prefixed as an internal EIEIO thingy and which holds the class 178 ;; properly prefixed as an internal EIEIO thingy and which holds the class
178 ;; object/struct in its `symbol-value' slot. 179 ;; object/struct in its `symbol-value' slot.
179 ((class-tag "tag containing the class struct"))) 180 class-tag)
181
182(eval-and-compile
183 (defconst eieio--object-num-slots
184 (length (get 'eieio--object 'cl-struct-slots))))
180 185
181(defsubst eieio--object-class-object (obj) 186(defsubst eieio--object-class-object (obj)
182 (symbol-value (eieio--object-class-tag obj))) 187 (symbol-value (eieio--object-class-tag obj)))
@@ -297,15 +302,11 @@ It creates an autoload function for CNAME's constructor."
297 ;; Assume we've already debugged inputs. 302 ;; Assume we've already debugged inputs.
298 303
299 (let* ((oldc (when (class-p cname) (eieio--class-v cname))) 304 (let* ((oldc (when (class-p cname) (eieio--class-v cname)))
300 (newc (make-vector eieio--class-num-slots nil)) 305 (newc (eieio--class-make cname))
301 ) 306 )
302 (if oldc 307 (if oldc
303 nil ;; Do nothing if we already have this class. 308 nil ;; Do nothing if we already have this class.
304 309
305 ;; Create the class in NEWC, but don't fill anything else in.
306 (aset newc 0 'defclass)
307 (setf (eieio--class-symbol newc) cname)
308
309 (let ((clear-parent nil)) 310 (let ((clear-parent nil))
310 ;; No parents? 311 ;; No parents?
311 (when (not superclasses) 312 (when (not superclasses)
@@ -333,7 +334,8 @@ It creates an autoload function for CNAME's constructor."
333 334
334 ;; turn this into a usable self-pointing symbol 335 ;; turn this into a usable self-pointing symbol
335 (when eieio-backward-compatibility 336 (when eieio-backward-compatibility
336 (set cname cname)) 337 (set cname cname)
338 (make-obsolete-variable cname (format "use '%s instead" cname) "25.1"))
337 339
338 ;; Store the new class vector definition into the symbol. We need to 340 ;; Store the new class vector definition into the symbol. We need to
339 ;; do this first so that we can call defmethod for the accessor. 341 ;; do this first so that we can call defmethod for the accessor.
@@ -364,11 +366,10 @@ It creates an autoload function for CNAME's constructor."
364 366
365(declare-function eieio--defmethod "eieio-generic" (method kind argclass code)) 367(declare-function eieio--defmethod "eieio-generic" (method kind argclass code))
366 368
367(defun eieio-defclass (cname superclasses slots options-and-doc) 369(defun eieio-defclass-internal (cname superclasses slots options)
368 ;; FIXME: Most of this should be moved to the `defclass' macro.
369 "Define CNAME as a new subclass of SUPERCLASSES. 370 "Define CNAME as a new subclass of SUPERCLASSES.
370SLOTS are the slots residing in that class definition, and options or 371SLOTS are the slots residing in that class definition, and OPTIONS
371documentation OPTIONS-AND-DOC is the toplevel documentation for this class. 372holds the class options.
372See `defclass' for more information." 373See `defclass' for more information."
373 ;; Run our eieio-hook each time, and clear it when we are done. 374 ;; Run our eieio-hook each time, and clear it when we are done.
374 ;; This way people can add hooks safely if they want to modify eieio 375 ;; This way people can add hooks safely if they want to modify eieio
@@ -376,18 +377,12 @@ See `defclass' for more information."
376 (run-hooks 'eieio-hook) 377 (run-hooks 'eieio-hook)
377 (setq eieio-hook nil) 378 (setq eieio-hook nil)
378 379
379 (eieio--check-type listp superclasses)
380
381 (let* ((pname superclasses) 380 (let* ((pname superclasses)
382 (newc (make-vector eieio--class-num-slots nil)) 381 (newc (eieio--class-make cname))
383 (oldc (when (class-p cname) (eieio--class-v cname))) 382 (oldc (when (class-p cname) (eieio--class-v cname)))
384 (groups nil) ;; list of groups id'd from slots 383 (groups nil) ;; list of groups id'd from slots
385 (options nil)
386 (clearparent nil)) 384 (clearparent nil))
387 385
388 (aset newc 0 'defclass)
389 (setf (eieio--class-symbol newc) cname)
390
391 ;; If this class already existed, and we are updating its structure, 386 ;; If this class already existed, and we are updating its structure,
392 ;; make sure we keep the old child list. This can cause bugs, but 387 ;; make sure we keep the old child list. This can cause bugs, but
393 ;; if no new slots are created, it also saves time, and prevents 388 ;; if no new slots are created, it also saves time, and prevents
@@ -403,19 +398,6 @@ See `defclass' for more information."
403 (setf (eieio--class-children newc) children) 398 (setf (eieio--class-children newc) children)
404 (remhash cname eieio-defclass-autoload-map)))) 399 (remhash cname eieio-defclass-autoload-map))))
405 400
406 (cond ((and (stringp (car options-and-doc))
407 (/= 1 (% (length options-and-doc) 2)))
408 (error "Too many arguments to `defclass'"))
409 ((and (symbolp (car options-and-doc))
410 (/= 0 (% (length options-and-doc) 2)))
411 (error "Too many arguments to `defclass'"))
412 )
413
414 (setq options
415 (if (stringp (car options-and-doc))
416 (cons :documentation options-and-doc)
417 options-and-doc))
418
419 (if pname 401 (if pname
420 (progn 402 (progn
421 (dolist (p pname) 403 (dolist (p pname)
@@ -447,52 +429,13 @@ See `defclass' for more information."
447 429
448 ;; turn this into a usable self-pointing symbol; FIXME: Why? 430 ;; turn this into a usable self-pointing symbol; FIXME: Why?
449 (when eieio-backward-compatibility 431 (when eieio-backward-compatibility
450 (set cname cname)) 432 (set cname cname)
451 433 (make-obsolete-variable cname (format "use '%s instead" cname) "25.1"))
452 ;; These two tests must be created right away so we can have self-
453 ;; referencing classes. ei, a class whose slot can contain only
454 ;; pointers to itself.
455
456 ;; Create the test function
457 (let ((csym (intern (concat (symbol-name cname) "-p"))))
458 (fset csym
459 `(lambda (obj)
460 ,(format "Test OBJ to see if it an object of type %s" cname)
461 (and (eieio-object-p obj)
462 (same-class-p obj ',cname)))))
463
464 ;; Make sure the method invocation order is a valid value.
465 (let ((io (eieio--class-option-assoc options :method-invocation-order)))
466 (when (and io (not (member io '(:depth-first :breadth-first :c3))))
467 (error "Method invocation order %s is not allowed" io)
468 ))
469
470 ;; Create a handy child test too
471 (let ((csym (if eieio-backward-compatibility
472 (intern (concat (symbol-name cname) "-child-p"))
473 (make-symbol (concat (symbol-name cname) "-child-p")))))
474 (fset csym
475 `(lambda (obj)
476 ,(format
477 "Test OBJ to see if it an object is a child of type %s"
478 cname)
479 (and (eieio-object-p obj)
480 (object-of-class-p obj ',cname))))
481
482 ;; When using typep, (typep OBJ 'myclass) returns t for objects which
483 ;; are subclasses of myclass. For our predicates, however, it is
484 ;; important for EIEIO to be backwards compatible, where
485 ;; myobject-p, and myobject-child-p are different.
486 ;; "cl" uses this technique to specify symbols with specific typep
487 ;; test, so we can let typep have the CLOS documented behavior
488 ;; while keeping our above predicate clean.
489
490 (put cname 'cl-deftype-satisfies csym))
491 434
492 ;; Create a handy list of the class test too 435 ;; Create a handy list of the class test too
493 (when eieio-backward-compatibility 436 (when eieio-backward-compatibility
494 (let ((csym (intern (concat (symbol-name cname) "-list-p")))) 437 (let ((csym (intern (concat (symbol-name cname) "-list-p"))))
495 (fset csym 438 (defalias csym
496 `(lambda (obj) 439 `(lambda (obj)
497 ,(format 440 ,(format
498 "Test OBJ to see if it a list of objects which are a child of type %s" 441 "Test OBJ to see if it a list of objects which are a child of type %s"
@@ -505,7 +448,10 @@ See `defclass' for more information."
505 (setq ans (and (eieio-object-p (car obj)) 448 (setq ans (and (eieio-object-p (car obj))
506 (object-of-class-p (car obj) ,cname))) 449 (object-of-class-p (car obj) ,cname)))
507 (setq obj (cdr obj))) 450 (setq obj (cdr obj)))
508 ans)))))) 451 ans))))
452 (make-obsolete csym (format "use (cl-typep ... '(list-of %s)) instead"
453 cname)
454 "25.1")))
509 455
510 ;; Before adding new slots, let's add all the methods and classes 456 ;; Before adding new slots, let's add all the methods and classes
511 ;; in from the parent class. 457 ;; in from the parent class.
@@ -519,19 +465,13 @@ See `defclass' for more information."
519 465
520 ;; Query each slot in the declaration list and mangle into the 466 ;; Query each slot in the declaration list and mangle into the
521 ;; class structure I have defined. 467 ;; class structure I have defined.
522 (while slots 468 (pcase-dolist (`(,name . ,slot) slots)
523 (let* ((slot1 (car slots)) 469 (let* ((init (or (plist-get slot :initform)
524 (name (car slot1))
525 (slot (cdr slot1))
526 (acces (plist-get slot :accessor))
527 (init (or (plist-get slot :initform)
528 (if (member :initform slot) nil 470 (if (member :initform slot) nil
529 eieio-unbound))) 471 eieio-unbound)))
530 (initarg (plist-get slot :initarg)) 472 (initarg (plist-get slot :initarg))
531 (docstr (plist-get slot :documentation)) 473 (docstr (plist-get slot :documentation))
532 (prot (plist-get slot :protection)) 474 (prot (plist-get slot :protection))
533 (reader (plist-get slot :reader))
534 (writer (plist-get slot :writer))
535 (alloc (plist-get slot :allocation)) 475 (alloc (plist-get slot :allocation))
536 (type (plist-get slot :type)) 476 (type (plist-get slot :type))
537 (custom (plist-get slot :custom)) 477 (custom (plist-get slot :custom))
@@ -542,51 +482,24 @@ See `defclass' for more information."
542 (skip-nil (eieio--class-option-assoc options :allow-nil-initform)) 482 (skip-nil (eieio--class-option-assoc options :allow-nil-initform))
543 ) 483 )
544 484
545 (if eieio-error-unsupported-class-tags
546 (let ((tmp slot))
547 (while tmp
548 (if (not (member (car tmp) '(:accessor
549 :initform
550 :initarg
551 :documentation
552 :protection
553 :reader
554 :writer
555 :allocation
556 :type
557 :custom
558 :label
559 :group
560 :printer
561 :allow-nil-initform
562 :custom-groups)))
563 (signal 'invalid-slot-type (list (car tmp))))
564 (setq tmp (cdr (cdr tmp))))))
565
566 ;; Clean up the meaning of protection. 485 ;; Clean up the meaning of protection.
567 (cond ((or (eq prot 'public) (eq prot :public)) (setq prot nil)) 486 (setq prot
568 ((or (eq prot 'protected) (eq prot :protected)) (setq prot 'protected)) 487 (pcase prot
569 ((or (eq prot 'private) (eq prot :private)) (setq prot 'private)) 488 ((or 'nil 'public ':public) nil)
570 ((eq prot nil) nil) 489 ((or 'protected ':protected) 'protected)
571 (t (signal 'invalid-slot-type (list :protection prot)))) 490 ((or 'private ':private) 'private)
572 491 (_ (signal 'invalid-slot-type (list :protection prot)))))
573 ;; Make sure the :allocation parameter has a valid value.
574 (if (not (or (not alloc) (eq alloc :class) (eq alloc :instance)))
575 (signal 'invalid-slot-type (list :allocation alloc)))
576 492
577 ;; The default type specifier is supposed to be t, meaning anything. 493 ;; The default type specifier is supposed to be t, meaning anything.
578 (if (not type) (setq type t)) 494 (if (not type) (setq type t))
579 495
580 ;; Label is nil, or a string
581 (if (not (or (null label) (stringp label)))
582 (signal 'invalid-slot-type (list :label label)))
583
584 ;; Is there an initarg, but allocation of class?
585 (if (and initarg (eq alloc :class))
586 (message "Class allocated slots do not need :initarg"))
587
588 ;; intern the symbol so we can use it blankly 496 ;; intern the symbol so we can use it blankly
589 (if initarg (set initarg initarg)) 497 (if eieio-backward-compatibility
498 (and initarg (not (keywordp initarg))
499 (progn
500 (set initarg initarg)
501 (make-obsolete-variable
502 initarg (format "use '%s instead" initarg) "25.1"))))
590 503
591 ;; The customgroup should be a list of symbols 504 ;; The customgroup should be a list of symbols
592 (cond ((null customg) 505 (cond ((null customg)
@@ -604,63 +517,9 @@ See `defclass' for more information."
604 prot initarg alloc 'defaultoverride skip-nil) 517 prot initarg alloc 'defaultoverride skip-nil)
605 518
606 ;; We need to id the group, and store them in a group list attribute. 519 ;; We need to id the group, and store them in a group list attribute.
607 (mapc (lambda (cg) (cl-pushnew cg groups :test 'equal)) customg) 520 (dolist (cg customg)
608 521 (cl-pushnew cg groups :test 'equal))
609 ;; Anyone can have an accessor function. This creates a function 522 ))
610 ;; of the specified name, and also performs a `defsetf' if applicable
611 ;; so that users can `setf' the space returned by this function.
612 (if acces
613 (progn
614 (eieio--defmethod
615 acces (if (eq alloc :class) :static :primary) cname
616 `(lambda (this)
617 ,(format
618 "Retrieves the slot `%s' from an object of class `%s'"
619 name cname)
620 (if (slot-boundp this ',name)
621 ;; Use oref-default for :class allocated slots, since
622 ;; these also accept the use of a class argument instead
623 ;; of an object argument.
624 (,(if (eq alloc :class) 'eieio-oref-default 'eieio-oref)
625 this ',name)
626 ;; Else - Some error? nil?
627 nil)))
628
629 ;; FIXME: We should move more of eieio-defclass into the
630 ;; defclass macro so we don't have to use `eval' and require
631 ;; `gv' at run-time.
632 ;; FIXME: The defmethod above only defines a part of the generic
633 ;; function, but the define-setter below affects the whole
634 ;; generic function!
635 (eval `(gv-define-setter ,acces (eieio--store eieio--object)
636 ;; Apparently, eieio-oset-default doesn't work like
637 ;; oref-default and only accept class arguments!
638 (list ',(if nil ;; (eq alloc :class)
639 'eieio-oset-default
640 'eieio-oset)
641 eieio--object '',name
642 eieio--store)))))
643
644 ;; If a writer is defined, then create a generic method of that
645 ;; name whose purpose is to set the value of the slot.
646 (if writer
647 (eieio--defmethod
648 writer nil cname
649 `(lambda (this value)
650 ,(format "Set the slot `%s' of an object of class `%s'"
651 name cname)
652 (setf (slot-value this ',name) value))))
653 ;; If a reader is defined, then create a generic method
654 ;; of that name whose purpose is to access this slot value.
655 (if reader
656 (eieio--defmethod
657 reader nil cname
658 `(lambda (this)
659 ,(format "Access the slot `%s' from object of class `%s'"
660 name cname)
661 (slot-value this ',name))))
662 )
663 (setq slots (cdr slots)))
664 523
665 ;; Now that everything has been loaded up, all our lists are backwards! 524 ;; Now that everything has been loaded up, all our lists are backwards!
666 ;; Fix that up now. 525 ;; Fix that up now.
@@ -700,30 +559,6 @@ See `defclass' for more information."
700 prots (cdr prots))) 559 prots (cdr prots)))
701 (setf (eieio--class-symbol-hashtable newc) oa)) 560 (setf (eieio--class-symbol-hashtable newc) oa))
702 561
703 ;; Create the constructor function
704 (if (eieio--class-option-assoc options :abstract)
705 ;; Abstract classes cannot be instantiated. Say so.
706 (let ((abs (eieio--class-option-assoc options :abstract)))
707 (if (not (stringp abs))
708 (setq abs (format "Class %s is abstract" cname)))
709 (fset cname
710 `(lambda (&rest stuff)
711 ,(format "You cannot create a new object of type %s" cname)
712 (error ,abs))))
713
714 ;; Non-abstract classes need a constructor.
715 (fset cname
716 `(lambda (&rest slots)
717 ,(format "Create a new object with name NAME of class type %s" cname)
718 (if (and slots
719 (let ((x (car slots)))
720 (or (stringp x) (null x))))
721 (funcall (if eieio-backward-compatibility #'ignore #'message)
722 "Obsolete name %S passed to %S constructor"
723 (pop slots) ',cname))
724 (apply #'eieio-constructor ',cname slots)))
725 )
726
727 ;; Set up a specialized doc string. 562 ;; Set up a specialized doc string.
728 ;; Use stored value since it is calculated in a non-trivial way 563 ;; Use stored value since it is calculated in a non-trivial way
729 (put cname 'variable-documentation 564 (put cname 'variable-documentation
@@ -1468,6 +1303,13 @@ method invocation orders of the involved classes."
1468(define-error 'unbound-slot "Unbound slot") 1303(define-error 'unbound-slot "Unbound slot")
1469(define-error 'inconsistent-class-hierarchy "Inconsistent class hierarchy") 1304(define-error 'inconsistent-class-hierarchy "Inconsistent class hierarchy")
1470 1305
1306;;; Backward compatibility functions
1307;; To support .elc files compiled for older versions of EIEIO.
1308
1309(defun eieio-defclass (cname superclasses slots options)
1310 (eval `(defclass ,cname ,superclasses ,slots ,options)))
1311
1312
1471(provide 'eieio-core) 1313(provide 'eieio-core)
1472 1314
1473;;; eieio-core.el ends here 1315;;; eieio-core.el ends here
diff --git a/lisp/emacs-lisp/eieio-opt.el b/lisp/emacs-lisp/eieio-opt.el
index 60bbd503adf..13ad120a9b5 100644
--- a/lisp/emacs-lisp/eieio-opt.el
+++ b/lisp/emacs-lisp/eieio-opt.el
@@ -230,7 +230,7 @@ Optional argument CLASS is the class to start with.
230If INSTANTIABLE-ONLY is non nil, only allow names of classes which 230If INSTANTIABLE-ONLY is non nil, only allow names of classes which
231are not abstract, otherwise allow all classes. 231are not abstract, otherwise allow all classes.
232Optional argument BUILDLIST is more list to attach and is used internally." 232Optional argument BUILDLIST is more list to attach and is used internally."
233 (let* ((cc (or class eieio-default-superclass)) 233 (let* ((cc (or class 'eieio-default-superclass))
234 (sublst (eieio--class-children (eieio--class-v cc)))) 234 (sublst (eieio--class-children (eieio--class-v cc))))
235 (unless (assoc (symbol-name cc) buildlist) 235 (unless (assoc (symbol-name cc) buildlist)
236 (when (or (not instantiable-only) (not (class-abstract-p cc))) 236 (when (or (not instantiable-only) (not (class-abstract-p cc)))
@@ -561,7 +561,7 @@ current expansion depth."
561 (when (eq (point-min) (point-max)) 561 (when (eq (point-min) (point-max))
562 ;; This function is only called once, to start the whole deal. 562 ;; This function is only called once, to start the whole deal.
563 ;; Create and expand the default object. 563 ;; Create and expand the default object.
564 (eieio-class-button eieio-default-superclass 0) 564 (eieio-class-button 'eieio-default-superclass 0)
565 (forward-line -1) 565 (forward-line -1)
566 (speedbar-expand-line))) 566 (speedbar-expand-line)))
567 567
diff --git a/lisp/emacs-lisp/eieio.el b/lisp/emacs-lisp/eieio.el
index bf51986b133..205f13108b8 100644
--- a/lisp/emacs-lisp/eieio.el
+++ b/lisp/emacs-lisp/eieio.el
@@ -58,13 +58,11 @@
58 58
59;;; Defining a new class 59;;; Defining a new class
60;; 60;;
61(defmacro defclass (name superclass slots &rest options-and-doc) 61(defmacro defclass (name superclasses slots &rest options-and-doc)
62 "Define NAME as a new class derived from SUPERCLASS with SLOTS. 62 "Define NAME as a new class derived from SUPERCLASS with SLOTS.
63OPTIONS-AND-DOC is used as the class' options and base documentation. 63OPTIONS-AND-DOC is used as the class' options and base documentation.
64SUPERCLASS is a list of superclasses to inherit from, with SLOTS 64SUPERCLASSES is a list of superclasses to inherit from, with SLOTS
65being the slots residing in that class definition. NOTE: Currently 65being the slots residing in that class definition. Supported tags are:
66only one slot may exist in SUPERCLASS as multiple inheritance is not
67yet supported. Supported tags are:
68 66
69 :initform - Initializing form. 67 :initform - Initializing form.
70 :initarg - Tag used during initialization. 68 :initarg - Tag used during initialization.
@@ -115,12 +113,178 @@ Options in CLOS not supported in EIEIO:
115Due to the way class options are set up, you can add any tags you wish, 113Due to the way class options are set up, you can add any tags you wish,
116and reference them using the function `class-option'." 114and reference them using the function `class-option'."
117 (declare (doc-string 4)) 115 (declare (doc-string 4))
118 ;; This is eval-and-compile only to silence spurious compiler warnings 116 (eieio--check-type listp superclasses)
119 ;; about functions and variables not known to be defined. 117
120 ;; When eieio-defclass code is merged here and this becomes 118 (cond ((and (stringp (car options-and-doc))
121 ;; transparent to the compiler, the eval-and-compile can be removed. 119 (/= 1 (% (length options-and-doc) 2)))
122 `(eval-and-compile 120 (error "Too many arguments to `defclass'"))
123 (eieio-defclass ',name ',superclass ',slots ',options-and-doc))) 121 ((and (symbolp (car options-and-doc))
122 (/= 0 (% (length options-and-doc) 2)))
123 (error "Too many arguments to `defclass'")))
124
125 (if (stringp (car options-and-doc))
126 (setq options-and-doc
127 (cons :documentation options-and-doc)))
128
129 ;; Make sure the method invocation order is a valid value.
130 (let ((io (eieio--class-option-assoc options-and-doc
131 :method-invocation-order)))
132 (when (and io (not (member io '(:depth-first :breadth-first :c3))))
133 (error "Method invocation order %s is not allowed" io)))
134
135 (let ((testsym1 (intern (concat (symbol-name name) "-p")))
136 (testsym2 (intern (format "eieio--childp--%s" name)))
137 (accessors ()))
138
139 ;; Collect the accessors we need to define.
140 (pcase-dolist (`(,sname . ,soptions) slots)
141 (let* ((acces (plist-get soptions :accessor))
142 (initarg (plist-get soptions :initarg))
143 (reader (plist-get soptions :reader))
144 (writer (plist-get soptions :writer))
145 (alloc (plist-get soptions :allocation))
146 (label (plist-get soptions :label)))
147
148 (if eieio-error-unsupported-class-tags
149 (let ((tmp soptions))
150 (while tmp
151 (if (not (member (car tmp) '(:accessor
152 :initform
153 :initarg
154 :documentation
155 :protection
156 :reader
157 :writer
158 :allocation
159 :type
160 :custom
161 :label
162 :group
163 :printer
164 :allow-nil-initform
165 :custom-groups)))
166 (signal 'invalid-slot-type (list (car tmp))))
167 (setq tmp (cdr (cdr tmp))))))
168
169 ;; Make sure the :allocation parameter has a valid value.
170 (if (not (memq alloc '(nil :class :instance)))
171 (signal 'invalid-slot-type (list :allocation alloc)))
172
173 ;; Label is nil, or a string
174 (if (not (or (null label) (stringp label)))
175 (signal 'invalid-slot-type (list :label label)))
176
177 ;; Is there an initarg, but allocation of class?
178 (if (and initarg (eq alloc :class))
179 (message "Class allocated slots do not need :initarg"))
180
181 ;; Anyone can have an accessor function. This creates a function
182 ;; of the specified name, and also performs a `defsetf' if applicable
183 ;; so that users can `setf' the space returned by this function.
184 (when acces
185 ;; FIXME: The defmethod below only defines a part of the generic
186 ;; function (good), but the define-setter below affects the whole
187 ;; generic function (bad)!
188 (push `(gv-define-setter ,acces (store object)
189 ;; Apparently, eieio-oset-default doesn't work like
190 ;; oref-default and only accept class arguments!
191 (list ',(if nil ;; (eq alloc :class)
192 'eieio-oset-default
193 'eieio-oset)
194 object '',sname store))
195 accessors)
196 (push `(defmethod ,acces ,(if (eq alloc :class) :static :primary)
197 ((this ,name))
198 ,(format
199 "Retrieve the slot `%S' from an object of class `%S'."
200 sname name)
201 (if (slot-boundp this ',sname)
202 ;; Use oref-default for :class allocated slots, since
203 ;; these also accept the use of a class argument instead
204 ;; of an object argument.
205 (,(if (eq alloc :class) 'eieio-oref-default 'eieio-oref)
206 this ',sname)
207 ;; Else - Some error? nil?
208 nil))
209 accessors))
210
211 ;; If a writer is defined, then create a generic method of that
212 ;; name whose purpose is to set the value of the slot.
213 (if writer
214 (push `(defmethod ,writer ((this ,name) value)
215 ,(format "Set the slot `%S' of an object of class `%S'."
216 sname name)
217 (setf (slot-value this ',sname) value))
218 accessors))
219 ;; If a reader is defined, then create a generic method
220 ;; of that name whose purpose is to access this slot value.
221 (if reader
222 (push `(defmethod ,reader ((this ,name))
223 ,(format "Access the slot `%S' from object of class `%S'."
224 sname name)
225 (slot-value this ',sname))
226 accessors))
227 ))
228
229 `(progn
230 ;; This test must be created right away so we can have self-
231 ;; referencing classes. ei, a class whose slot can contain only
232 ;; pointers to itself.
233
234 ;; Create the test function.
235 (defun ,testsym1 (obj)
236 ,(format "Test OBJ to see if it an object of type %S." name)
237 (and (eieio-object-p obj)
238 (same-class-p obj ',name)))
239
240 (defun ,testsym2 (obj)
241 ,(format
242 "Test OBJ to see if it an object is a child of type %S."
243 name)
244 (and (eieio-object-p obj)
245 (object-of-class-p obj ',name)))
246
247 ,@(when eieio-backward-compatibility
248 (let ((f (intern (format "%s-child-p" name))))
249 `((defalias ',f ',testsym2)
250 (make-obsolete
251 ',f ,(format "use (cl-typep ... '%s) instead" name) "25.1"))))
252
253 ;; When using typep, (typep OBJ 'myclass) returns t for objects which
254 ;; are subclasses of myclass. For our predicates, however, it is
255 ;; important for EIEIO to be backwards compatible, where
256 ;; myobject-p, and myobject-child-p are different.
257 ;; "cl" uses this technique to specify symbols with specific typep
258 ;; test, so we can let typep have the CLOS documented behavior
259 ;; while keeping our above predicate clean.
260
261 (put ',name 'cl-deftype-satisfies #',testsym2)
262
263 (eieio-defclass-internal ',name ',superclasses ',slots ',options-and-doc)
264
265 ,@accessors
266
267 ;; Create the constructor function
268 ,(if (eieio--class-option-assoc options-and-doc :abstract)
269 ;; Abstract classes cannot be instantiated. Say so.
270 (let ((abs (eieio--class-option-assoc options-and-doc :abstract)))
271 (if (not (stringp abs))
272 (setq abs (format "Class %s is abstract" name)))
273 `(defun ,name (&rest _)
274 ,(format "You cannot create a new object of type %S." name)
275 (error ,abs)))
276
277 ;; Non-abstract classes need a constructor.
278 `(defun ,name (&rest slots)
279 ,(format "Create a new object with name NAME of class type %S."
280 name)
281 (if (and slots
282 (let ((x (car slots)))
283 (or (stringp x) (null x))))
284 (funcall (if eieio-backward-compatibility #'ignore #'message)
285 "Obsolete name %S passed to %S constructor"
286 (pop slots) ',name))
287 (apply #'eieio-constructor ',name slots))))))
124 288
125 289
126;;; CLOS style implementation of object creators. 290;;; CLOS style implementation of object creators.