]> code.delx.au - gnu-emacs/blob - lisp/emacs-lisp/eieio-generic.el
* lisp/emacs-lisp/cl-generic.el: Add support for cl-next-method-p.
[gnu-emacs] / lisp / emacs-lisp / eieio-generic.el
1 ;;; eieio-generic.el --- CLOS-style generics for EIEIO -*- lexical-binding:t -*-
2
3 ;; Copyright (C) 1995-1996, 1998-2015 Free Software Foundation, Inc.
4
5 ;; Author: Eric M. Ludlam <zappo@gnu.org>
6 ;; Keywords: OO, lisp
7
8 ;; This file is part of GNU Emacs.
9
10 ;; GNU Emacs is free software: you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation, either version 3 of the License, or
13 ;; (at your option) any later version.
14
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
22
23 ;;; Commentary:
24 ;;
25 ;; The "core" part of EIEIO is the implementation for the object
26 ;; system (such as eieio-defclass, or eieio-defmethod) but not the
27 ;; base classes for the object system, which are defined in EIEIO.
28 ;;
29 ;; See the commentary for eieio.el for more about EIEIO itself.
30
31 ;;; Code:
32
33 (require 'eieio-core)
34 (declare-function child-of-class-p "eieio")
35
36 (put 'eieio--defalias 'byte-hunk-handler
37 #'byte-compile-file-form-defalias) ;;(get 'defalias 'byte-hunk-handler)
38 (defun eieio--defalias (name body)
39 "Like `defalias', but with less side-effects.
40 More specifically, it has no side-effects at all when the new function
41 definition is the same (`eq') as the old one."
42 (while (and (fboundp name) (symbolp (symbol-function name)))
43 ;; Follow aliases, so methods applied to obsolete aliases still work.
44 (setq name (symbol-function name)))
45 (unless (and (fboundp name)
46 (eq (symbol-function name) body))
47 (defalias name body)))
48
49 (defconst eieio--method-static 0 "Index into :static tag on a method.")
50 (defconst eieio--method-before 1 "Index into :before tag on a method.")
51 (defconst eieio--method-primary 2 "Index into :primary tag on a method.")
52 (defconst eieio--method-after 3 "Index into :after tag on a method.")
53 (defconst eieio--method-num-lists 4 "Number of indexes into methods vector in which groups of functions are kept.")
54 (defconst eieio--method-generic-before 4 "Index into generic :before tag on a method.")
55 (defconst eieio--method-generic-primary 5 "Index into generic :primary tag on a method.")
56 (defconst eieio--method-generic-after 6 "Index into generic :after tag on a method.")
57 (defconst eieio--method-num-slots 7 "Number of indexes into a method's vector.")
58
59 (defsubst eieio--specialized-key-to-generic-key (key)
60 "Convert a specialized KEY into a generic method key."
61 (cond ((eq key eieio--method-static) 0) ;; don't convert
62 ((< key eieio--method-num-lists) (+ key 3)) ;; The conversion
63 (t key) ;; already generic.. maybe.
64 ))
65
66 \f
67 (defsubst generic-p (method)
68 "Return non-nil if symbol METHOD is a generic function.
69 Only methods have the symbol `eieio-method-hashtable' as a property
70 \(which contains a list of all bindings to that method type.)"
71 (and (fboundp method) (get method 'eieio-method-hashtable)))
72
73 (defun eieio--generic-primary-only-p (method)
74 "Return t if symbol METHOD is a generic function with only primary methods.
75 Only methods have the symbol `eieio-method-hashtable' as a property (which
76 contains a list of all bindings to that method type.)
77 Methods with only primary implementations are executed in an optimized way."
78 (and (generic-p method)
79 (let ((M (get method 'eieio-method-tree)))
80 (not (or (>= 0 (length (aref M eieio--method-primary)))
81 (aref M eieio--method-static)
82 (aref M eieio--method-before)
83 (aref M eieio--method-after)
84 (aref M eieio--method-generic-before)
85 (aref M eieio--method-generic-primary)
86 (aref M eieio--method-generic-after)))
87 )))
88
89 (defun eieio--generic-primary-only-one-p (method)
90 "Return t if symbol METHOD is a generic function with only primary methods.
91 Only methods have the symbol `eieio-method-hashtable' as a property (which
92 contains a list of all bindings to that method type.)
93 Methods with only primary implementations are executed in an optimized way."
94 (and (generic-p method)
95 (let ((M (get method 'eieio-method-tree)))
96 (not (or (/= 1 (length (aref M eieio--method-primary)))
97 (aref M eieio--method-static)
98 (aref M eieio--method-before)
99 (aref M eieio--method-after)
100 (aref M eieio--method-generic-before)
101 (aref M eieio--method-generic-primary)
102 (aref M eieio--method-generic-after)))
103 )))
104
105 (defun eieio--defgeneric-init-form (method doc-string)
106 "Form to use for the initial definition of a generic."
107 (while (and (fboundp method) (symbolp (symbol-function method)))
108 ;; Follow aliases, so methods applied to obsolete aliases still work.
109 (setq method (symbol-function method)))
110
111 (cond
112 ((or (not (fboundp method))
113 (eq 'autoload (car-safe (symbol-function method))))
114 ;; Make sure the method tables are installed.
115 (eieio--mt-install method)
116 ;; Construct the actual body of this function.
117 (if doc-string (put method 'function-documentation doc-string))
118 (eieio--defgeneric-form method))
119 ((generic-p method) (symbol-function method)) ;Leave it as-is.
120 (t (error "You cannot create a generic/method over an existing symbol: %s"
121 method))))
122
123 (defun eieio--defgeneric-form (method)
124 "The lambda form that would be used as the function defined on METHOD.
125 All methods should call the same EIEIO function for dispatch.
126 DOC-STRING is the documentation attached to METHOD."
127 (lambda (&rest local-args)
128 (eieio--generic-call method local-args)))
129
130 (defun eieio--defgeneric-form-primary-only (method)
131 "The lambda form that would be used as the function defined on METHOD.
132 All methods should call the same EIEIO function for dispatch.
133 DOC-STRING is the documentation attached to METHOD."
134 (lambda (&rest local-args)
135 (eieio--generic-call-primary-only method local-args)))
136
137 (defvar eieio--generic-call-arglst nil
138 "When using `call-next-method', provides a context for parameters.")
139 (defvar eieio--generic-call-key nil
140 "When using `call-next-method', provides a context for the current key.
141 Keys are a number representing :before, :primary, and :after methods.")
142 (defvar eieio--generic-call-next-method-list nil
143 "When executing a PRIMARY or STATIC method, track the 'next-method'.
144 During executions, the list is first generated, then as each next method
145 is called, the next method is popped off the stack.")
146
147 (defun eieio--defgeneric-form-primary-only-one (method class impl)
148 "The lambda form that would be used as the function defined on METHOD.
149 All methods should call the same EIEIO function for dispatch.
150 CLASS is the class symbol needed for private method access.
151 IMPL is the symbol holding the method implementation."
152 (lambda (&rest local-args)
153 ;; This is a cool cheat. Usually we need to look up in the
154 ;; method table to find out if there is a method or not. We can
155 ;; instead make that determination at load time when there is
156 ;; only one method. If the first arg is not a child of the class
157 ;; of that one implementation, then clearly, there is no method def.
158 (if (not (eieio-object-p (car local-args)))
159 ;; Not an object. Just signal.
160 (signal 'no-method-definition
161 (list method local-args))
162
163 ;; We do have an object. Make sure it is the right type.
164 (if (not (child-of-class-p (eieio--object-class-object (car local-args))
165 class))
166
167 ;; If not the right kind of object, call no applicable
168 (apply #'no-applicable-method (car local-args)
169 method local-args)
170
171 ;; It is ok, do the call.
172 ;; Fill in inter-call variables then evaluate the method.
173 (let ((eieio--generic-call-next-method-list nil)
174 (eieio--generic-call-key eieio--method-primary)
175 (eieio--generic-call-arglst local-args)
176 )
177 (apply impl local-args))))))
178
179 (defun eieio-unbind-method-implementations (method)
180 "Make the generic method METHOD have no implementations.
181 It will leave the original generic function in place,
182 but remove reference to all implementations of METHOD."
183 (put method 'eieio-method-tree nil)
184 (put method 'eieio-method-hashtable nil))
185
186 (defun eieio--method-optimize-primary (method)
187 (when eieio-optimize-primary-methods-flag
188 ;; Optimizing step:
189 ;;
190 ;; If this method, after this setup, only has primary methods, then
191 ;; we can setup the generic that way.
192 ;; Use `defalias' so as to interact properly with nadvice.el.
193 (defalias method
194 (if (eieio--generic-primary-only-p method)
195 ;; If there is only one primary method, then we can go one more
196 ;; optimization step.
197 (if (eieio--generic-primary-only-one-p method)
198 (let* ((M (get method 'eieio-method-tree))
199 (entry (car (aref M eieio--method-primary))))
200 (eieio--defgeneric-form-primary-only-one
201 method (car entry) (cdr entry)))
202 (eieio--defgeneric-form-primary-only method))
203 (eieio--defgeneric-form method)))))
204
205 (defun eieio--defmethod (method kind argclass code)
206 "Work part of the `defmethod' macro defining METHOD with ARGS."
207 (let ((key
208 ;; Find optional keys.
209 (cond ((memq kind '(:BEFORE :before)) eieio--method-before)
210 ((memq kind '(:AFTER :after)) eieio--method-after)
211 ((memq kind '(:STATIC :static)) eieio--method-static)
212 ((memq kind '(:PRIMARY :primary nil)) eieio--method-primary)
213 ;; Primary key.
214 ;; (t eieio--method-primary)
215 (t (error "Unknown method kind %S" kind)))))
216
217 (while (and (fboundp method) (symbolp (symbol-function method)))
218 ;; Follow aliases, so methods applied to obsolete aliases still work.
219 (setq method (symbol-function method)))
220
221 ;; Make sure there is a generic (when called from defclass).
222 (eieio--defalias
223 method (eieio--defgeneric-init-form
224 method (or (documentation code)
225 (format "Generically created method `%s'." method))))
226 ;; Create symbol for property to bind to. If the first arg is of
227 ;; the form (varname vartype) and `vartype' is a class, then
228 ;; that class will be the type symbol. If not, then it will fall
229 ;; under the type `primary' which is a non-specific calling of the
230 ;; function.
231 (if argclass
232 (if (not (class-p argclass)) ;FIXME: Accept cl-defstructs!
233 (error "Unknown class type %s in method parameters"
234 argclass))
235 ;; Generics are higher.
236 (setq key (eieio--specialized-key-to-generic-key key)))
237 ;; Put this lambda into the symbol so we can find it.
238 (eieio--mt-add method code key argclass)
239 )
240
241 (eieio--method-optimize-primary method)
242
243 method)
244
245 (define-obsolete-variable-alias 'eieio-pre-method-execution-hooks
246 'eieio-pre-method-execution-functions "24.3")
247 (defvar eieio-pre-method-execution-functions nil
248 "Abnormal hook run just before an EIEIO method is executed.
249 The hook function must accept one argument, the list of forms
250 about to be executed.")
251
252 (defun eieio--generic-call (method args)
253 "Call METHOD with ARGS.
254 ARGS provides the context on which implementation to use.
255 This should only be called from a generic function."
256 ;; We must expand our arguments first as they are always
257 ;; passed in as quoted symbols
258 (let ((newargs nil) (mclass nil) (lambdas nil) (tlambdas nil) (keys nil)
259 (eieio--generic-call-arglst args)
260 (firstarg nil)
261 (primarymethodlist nil))
262 ;; get a copy
263 (setq newargs args
264 firstarg (car newargs))
265 ;; Is the class passed in autoloaded?
266 ;; Since class names are also constructors, they can be autoloaded
267 ;; via the autoload command. Check for this, and load them in.
268 ;; It is ok if it doesn't turn out to be a class. Probably want that
269 ;; function loaded anyway.
270 (if (and (symbolp firstarg)
271 (fboundp firstarg)
272 (autoloadp (symbol-function firstarg)))
273 (autoload-do-load (symbol-function firstarg)))
274 ;; Determine the class to use.
275 (cond ((eieio-object-p firstarg)
276 (setq mclass (eieio--object-class-name firstarg)))
277 ((class-p firstarg)
278 (setq mclass firstarg))
279 )
280 ;; Make sure the class is a valid class
281 ;; mclass can be nil (meaning a generic for should be used.
282 ;; mclass cannot have a value that is not a class, however.
283 (unless (or (null mclass) (class-p mclass))
284 (error "Cannot dispatch method %S on class %S"
285 method mclass)
286 )
287 ;; Now create a list in reverse order of all the calls we have
288 ;; make in order to successfully do this right. Rules:
289 ;; 1) Only call static if this is a static method.
290 ;; 2) Only call specifics if the definition allows for them.
291 ;; 3) Call in order based on :before, :primary, and :after
292 (when (eieio-object-p firstarg)
293 ;; Non-static calls do all this stuff.
294
295 ;; :after methods
296 (setq tlambdas
297 (if mclass
298 (eieio--mt-method-list method eieio--method-after mclass)
299 (list (eieio--generic-form method eieio--method-after nil)))
300 ;;(or (and mclass (eieio--generic-form method eieio--method-after mclass))
301 ;; (eieio--generic-form method eieio--method-after nil))
302 )
303 (setq lambdas (append tlambdas lambdas)
304 keys (append (make-list (length tlambdas) eieio--method-after) keys))
305
306 ;; :primary methods
307 (setq tlambdas
308 (or (and mclass (eieio--generic-form method eieio--method-primary mclass))
309 (eieio--generic-form method eieio--method-primary nil)))
310 (when tlambdas
311 (setq lambdas (cons tlambdas lambdas)
312 keys (cons eieio--method-primary keys)
313 primarymethodlist
314 (eieio--mt-method-list method eieio--method-primary mclass)))
315
316 ;; :before methods
317 (setq tlambdas
318 (if mclass
319 (eieio--mt-method-list method eieio--method-before mclass)
320 (list (eieio--generic-form method eieio--method-before nil)))
321 ;;(or (and mclass (eieio--generic-form method eieio--method-before mclass))
322 ;; (eieio--generic-form method eieio--method-before nil))
323 )
324 (setq lambdas (append tlambdas lambdas)
325 keys (append (make-list (length tlambdas) eieio--method-before) keys))
326 )
327
328 (if mclass
329 ;; For the case of a class,
330 ;; if there were no methods found, then there could be :static methods.
331 (when (not lambdas)
332 (setq tlambdas
333 (eieio--generic-form method eieio--method-static mclass))
334 (setq lambdas (cons tlambdas lambdas)
335 keys (cons eieio--method-static keys)
336 primarymethodlist ;; Re-use even with bad name here
337 (eieio--mt-method-list method eieio--method-static mclass)))
338 ;; For the case of no class (ie - mclass == nil) then there may
339 ;; be a primary method.
340 (setq tlambdas
341 (eieio--generic-form method eieio--method-primary nil))
342 (when tlambdas
343 (setq lambdas (cons tlambdas lambdas)
344 keys (cons eieio--method-primary keys)
345 primarymethodlist
346 (eieio--mt-method-list method eieio--method-primary nil)))
347 )
348
349 (run-hook-with-args 'eieio-pre-method-execution-functions
350 primarymethodlist)
351
352 ;; Now loop through all occurrences forms which we must execute
353 ;; (which are happily sorted now) and execute them all!
354 (let ((rval nil) (lastval nil) (found nil))
355 (while lambdas
356 (if (car lambdas)
357 (let* ((eieio--generic-call-key (car keys))
358 (has-return-val
359 (or (= eieio--generic-call-key eieio--method-primary)
360 (= eieio--generic-call-key eieio--method-static)))
361 (eieio--generic-call-next-method-list
362 ;; Use the cdr, as the first element is the fcn
363 ;; we are calling right now.
364 (when has-return-val (cdr primarymethodlist)))
365 )
366 (setq found t)
367 ;;(setq rval (apply (car (car lambdas)) newargs))
368 (setq lastval (apply (car (car lambdas)) newargs))
369 (when has-return-val
370 (setq rval lastval))
371 ))
372 (setq lambdas (cdr lambdas)
373 keys (cdr keys)))
374 (if (not found)
375 (if (eieio-object-p (car args))
376 (setq rval (apply #'no-applicable-method (car args) method args))
377 (signal
378 'no-method-definition
379 (list method args))))
380 rval)))
381
382 (defun eieio--generic-call-primary-only (method args)
383 "Call METHOD with ARGS for methods with only :PRIMARY implementations.
384 ARGS provides the context on which implementation to use.
385 This should only be called from a generic function.
386
387 This method is like `eieio--generic-call', but only
388 implementations in the :PRIMARY slot are queried. After many
389 years of use, it appears that over 90% of methods in use
390 have :PRIMARY implementations only. We can therefore optimize
391 for this common case to improve performance."
392 ;; We must expand our arguments first as they are always
393 ;; passed in as quoted symbols
394 (let ((newargs nil) (mclass nil) (lambdas nil)
395 (eieio--generic-call-arglst args)
396 (firstarg nil)
397 (primarymethodlist nil)
398 )
399 ;; get a copy
400 (setq newargs args
401 firstarg (car newargs))
402
403 ;; Determine the class to use.
404 (cond ((eieio-object-p firstarg)
405 (setq mclass (eieio--object-class-name firstarg)))
406 ((not firstarg)
407 (error "Method %s called on nil" method))
408 (t
409 (error "Primary-only method %s called on something not an object" method)))
410 ;; Make sure the class is a valid class
411 ;; mclass can be nil (meaning a generic for should be used.
412 ;; mclass cannot have a value that is not a class, however.
413 (when (null mclass)
414 (error "Cannot dispatch method %S on class %S" method mclass)
415 )
416
417 ;; :primary methods
418 (setq lambdas (eieio--generic-form method eieio--method-primary mclass))
419 (setq primarymethodlist ;; Re-use even with bad name here
420 (eieio--mt-method-list method eieio--method-primary mclass))
421
422 ;; Now loop through all occurrences forms which we must execute
423 ;; (which are happily sorted now) and execute them all!
424 (let* ((rval nil) (lastval nil)
425 (eieio--generic-call-key eieio--method-primary)
426 ;; Use the cdr, as the first element is the fcn
427 ;; we are calling right now.
428 (eieio--generic-call-next-method-list (cdr primarymethodlist))
429 )
430
431 (if (or (not lambdas) (not (car lambdas)))
432
433 ;; No methods found for this impl...
434 (if (eieio-object-p (car args))
435 (setq rval (apply #'no-applicable-method
436 (car args) method args))
437 (signal
438 'no-method-definition
439 (list method args)))
440
441 ;; Do the regular implementation here.
442
443 (run-hook-with-args 'eieio-pre-method-execution-functions
444 lambdas)
445
446 (setq lastval (apply (car lambdas) newargs))
447 (setq rval lastval))
448
449 rval)))
450
451 (defun eieio--mt-method-list (method key class)
452 "Return an alist list of methods lambdas.
453 METHOD is the method name.
454 KEY represents either :before, or :after methods.
455 CLASS is the starting class to search from in the method tree.
456 If CLASS is nil, then an empty list of methods should be returned."
457 ;; Note: eieiomt - the MT means MethodTree. See more comments below
458 ;; for the rest of the eieiomt methods.
459
460 ;; Collect lambda expressions stored for the class and its parent
461 ;; classes.
462 (let (lambdas)
463 (dolist (ancestor (eieio--class-precedence-list (eieio--class-v class)))
464 ;; Lookup the form to use for the PRIMARY object for the next level
465 (let ((tmpl (eieio--generic-form method key ancestor)))
466 (when (and tmpl
467 (or (not lambdas)
468 ;; This prevents duplicates coming out of the
469 ;; class method optimizer. Perhaps we should
470 ;; just not optimize before/afters?
471 (not (member tmpl lambdas))))
472 (push tmpl lambdas))))
473
474 ;; Return collected lambda. For :after methods, return in current
475 ;; order (most general class last); Otherwise, reverse order.
476 (if (eq key eieio--method-after)
477 lambdas
478 (nreverse lambdas))))
479
480 \f
481 ;;;
482 ;; eieio-method-tree : eieio--mt-
483 ;;
484 ;; Stored as eieio-method-tree in property list of a generic method
485 ;;
486 ;; (eieio-method-tree . [BEFORE PRIMARY AFTER
487 ;; genericBEFORE genericPRIMARY genericAFTER])
488 ;; and
489 ;; (eieio-method-hashtable . [BEFORE PRIMARY AFTER
490 ;; genericBEFORE genericPRIMARY genericAFTER])
491 ;; where the association is a vector.
492 ;; (aref 0 -- all static methods.
493 ;; (aref 1 -- all methods classified as :before
494 ;; (aref 2 -- all methods classified as :primary
495 ;; (aref 3 -- all methods classified as :after
496 ;; (aref 4 -- a generic classified as :before
497 ;; (aref 5 -- a generic classified as :primary
498 ;; (aref 6 -- a generic classified as :after
499 ;;
500 (defvar eieio--mt--optimizing-hashtable nil
501 "While mapping atoms, this contain the hashtable being optimized.")
502
503 (defun eieio--mt-install (method-name)
504 "Install the method tree, and hashtable onto METHOD-NAME.
505 Do not do the work if they already exist."
506 (unless (and (get method-name 'eieio-method-tree)
507 (get method-name 'eieio-method-hashtable))
508 (put method-name 'eieio-method-tree
509 (make-vector eieio--method-num-slots nil))
510 (let ((emto (put method-name 'eieio-method-hashtable
511 (make-vector eieio--method-num-slots nil))))
512 (aset emto 0 (make-hash-table :test 'eq))
513 (aset emto 1 (make-hash-table :test 'eq))
514 (aset emto 2 (make-hash-table :test 'eq))
515 (aset emto 3 (make-hash-table :test 'eq)))))
516
517 (defun eieio--mt-add (method-name method key class)
518 "Add to METHOD-NAME the forms METHOD in a call position KEY for CLASS.
519 METHOD-NAME is the name created by a call to `defgeneric'.
520 METHOD are the forms for a given implementation.
521 KEY is an integer (see comment in eieio.el near this function) which
522 is associated with the :static :before :primary and :after tags.
523 It also indicates if CLASS is defined or not.
524 CLASS is the class this method is associated with."
525 (if (or (> key eieio--method-num-slots) (< key 0))
526 (error "eieio--mt-add: method key error!"))
527 (let ((emtv (get method-name 'eieio-method-tree))
528 (emto (get method-name 'eieio-method-hashtable)))
529 ;; Make sure the method tables are available.
530 (unless (and emtv emto)
531 (error "Programmer error: eieio--mt-add"))
532 ;; only add new cells on if it doesn't already exist!
533 (if (assq class (aref emtv key))
534 (setcdr (assq class (aref emtv key)) method)
535 (aset emtv key (cons (cons class method) (aref emtv key))))
536 ;; Add function definition into newly created symbol, and store
537 ;; said symbol in the correct hashtable, otherwise use the
538 ;; other array to keep this stuff.
539 (if (< key eieio--method-num-lists)
540 (puthash (eieio--class-v class) (list method) (aref emto key)))
541 ;; Save the defmethod file location in a symbol property.
542 (let ((fname (if load-in-progress
543 load-file-name
544 buffer-file-name)))
545 (when fname
546 (when (string-match "\\.elc\\'" fname)
547 (setq fname (substring fname 0 (1- (length fname)))))
548 (cl-pushnew (list class fname) (get method-name 'method-locations)
549 :test 'equal)))
550 ;; Now optimize the entire hashtable.
551 (if (< key eieio--method-num-lists)
552 (let ((eieio--mt--optimizing-hashtable (aref emto key)))
553 ;; @todo - Is this overkill? Should we just clear the symbol?
554 (maphash #'eieio--mt--sym-optimize eieio--mt--optimizing-hashtable)))
555 ))
556
557 (defun eieio--mt-next (class)
558 "Return the next parent class for CLASS.
559 If CLASS is a superclass, return variable `eieio-default-superclass'.
560 If CLASS is variable `eieio-default-superclass' then return nil.
561 This is different from function `class-parent' as class parent returns
562 nil for superclasses. This function performs no type checking!"
563 ;; No type-checking because all calls are made from functions which
564 ;; are safe and do checking for us.
565 (or (eieio--class-parent (eieio--class-v class))
566 (if (eq class 'eieio-default-superclass)
567 nil
568 '(eieio-default-superclass))))
569
570 (defun eieio--mt--sym-optimize (class s)
571 "Find the next class above S which has a function body for the optimizer."
572 ;; Set the value to nil in case there is no nearest cell.
573 (setcdr s nil)
574 ;; Find the nearest cell that has a function body. If we find one,
575 ;; we replace the nil from above.
576 (catch 'done
577 (dolist (ancestor
578 (cl-rest (eieio--class-precedence-list class)))
579 (let ((ov (gethash ancestor eieio--mt--optimizing-hashtable)))
580 (when (car ov)
581 (setcdr s ancestor) ;; store ov as our next symbol
582 (throw 'done ancestor))))))
583
584 (defun eieio--generic-form (method key class)
585 "Return the lambda form belonging to METHOD using KEY based upon CLASS.
586 If CLASS is not a class then use `generic' instead. If class has
587 no form, but has a parent class, then trace to that parent class.
588 The first time a form is requested from a symbol, an optimized path
589 is memorized for faster future use."
590 (if (symbolp class) (setq class (eieio--class-v class)))
591 (let ((emto (aref (get method 'eieio-method-hashtable)
592 (if class key (eieio--specialized-key-to-generic-key key)))))
593 (if (eieio--class-p class)
594 ;; 1) find our symbol
595 (let ((cs (gethash class emto)))
596 (unless cs
597 ;; 2) If there isn't one, then make one.
598 ;; This can be slow since it only occurs once
599 (puthash class (setq cs (list nil)) emto)
600 ;; 2.1) Cache its nearest neighbor with a quick optimize
601 ;; which should only occur once for this call ever
602 (let ((eieio--mt--optimizing-hashtable emto))
603 (eieio--mt--sym-optimize class cs)))
604 ;; 3) If it's bound return this one.
605 (if (car cs)
606 (cons (car cs) class)
607 ;; 4) If it's not bound then this variable knows something
608 (if (cdr cs)
609 (progn
610 ;; 4.1) This symbol holds the next class in its value
611 (setq class (cdr cs)
612 cs (gethash class emto))
613 ;; 4.2) The optimizer should always have chosen a
614 ;; function-symbol
615 ;;(if (car cs)
616 (cons (car cs) class)
617 ;;(error "EIEIO optimizer: erratic data loss!"))
618 )
619 ;; There never will be a funcall...
620 nil)))
621 ;; for a generic call, what is a list, is the function body we want.
622 (let ((emtl (aref (get method 'eieio-method-tree)
623 (if class key (eieio--specialized-key-to-generic-key key)))))
624 (if emtl
625 ;; The car of EMTL is supposed to be a class, which in this
626 ;; case is nil, so skip it.
627 (cons (cdr (car emtl)) nil)
628 nil)))))
629
630 \f
631 (define-error 'no-method-definition "No method definition")
632 (define-error 'no-next-method "No next method")
633
634 ;;; CLOS methods and generics
635 ;;
636 (defmacro defgeneric (method args &optional doc-string)
637 "Create a generic function METHOD.
638 DOC-STRING is the base documentation for this class. A generic
639 function has no body, as its purpose is to decide which method body
640 is appropriate to use. Uses `defmethod' to create methods, and calls
641 `defgeneric' for you. With this implementation the ARGS are
642 currently ignored. You can use `defgeneric' to apply specialized
643 top level documentation to a method."
644 (declare (doc-string 3))
645 `(eieio--defalias ',method
646 (eieio--defgeneric-init-form
647 ',method
648 ,(if doc-string (help-add-fundoc-usage doc-string args)))))
649
650 (defmacro defmethod (method &rest args)
651 "Create a new METHOD through `defgeneric' with ARGS.
652
653 The optional second argument KEY is a specifier that
654 modifies how the method is called, including:
655 :before - Method will be called before the :primary
656 :primary - The default if not specified
657 :after - Method will be called after the :primary
658 :static - First arg could be an object or class
659 The next argument is the ARGLIST. The ARGLIST specifies the arguments
660 to the method as with `defun'. The first argument can have a type
661 specifier, such as:
662 ((VARNAME CLASS) ARG2 ...)
663 where VARNAME is the name of the local variable for the method being
664 created. The CLASS is a class symbol for a class made with `defclass'.
665 A DOCSTRING comes after the ARGLIST, and is optional.
666 All the rest of the args are the BODY of the method. A method will
667 return the value of the last form in the BODY.
668
669 Summary:
670
671 (defmethod mymethod [:before | :primary | :after | :static]
672 ((typearg class-name) arg2 &optional opt &rest rest)
673 \"doc-string\"
674 body)"
675 (declare (doc-string 3)
676 (debug
677 (&define ; this means we are defining something
678 [&or name ("setf" :name setf name)]
679 ;; ^^ This is the methods symbol
680 [ &optional symbolp ] ; this is key :before etc
681 list ; arguments
682 [ &optional stringp ] ; documentation string
683 def-body ; part to be debugged
684 )))
685 (let* ((key (if (keywordp (car args)) (pop args)))
686 (params (car args))
687 (arg1 (car params))
688 (fargs (if (consp arg1)
689 (cons (car arg1) (cdr params))
690 params))
691 (class (if (consp arg1) (nth 1 arg1)))
692 (code `(lambda ,fargs ,@(cdr args))))
693 `(progn
694 ;; Make sure there is a generic and the byte-compiler sees it.
695 (defgeneric ,method ,args)
696 (eieio--defmethod ',method ',key ',class #',code))))
697
698
699
700 ;;;
701 ;; Method Calling Functions
702
703 (defun next-method-p ()
704 "Return non-nil if there is a next method.
705 Returns a list of lambda expressions which is the `next-method'
706 order."
707 eieio--generic-call-next-method-list)
708
709 (defun call-next-method (&rest replacement-args)
710 "Call the superclass method from a subclass method.
711 The superclass method is specified in the current method list,
712 and is called the next method.
713
714 If REPLACEMENT-ARGS is non-nil, then use them instead of
715 `eieio--generic-call-arglst'. The generic arg list are the
716 arguments passed in at the top level.
717
718 Use `next-method-p' to find out if there is a next method to call."
719 (if (and (/= eieio--generic-call-key eieio--method-primary)
720 (/= eieio--generic-call-key eieio--method-static))
721 (error "Cannot `call-next-method' except in :primary or :static methods")
722 )
723 (let ((newargs (or replacement-args eieio--generic-call-arglst))
724 (next (car eieio--generic-call-next-method-list))
725 )
726 (if (not (and next (car next)))
727 (apply #'no-next-method newargs)
728 (let* ((eieio--generic-call-next-method-list
729 (cdr eieio--generic-call-next-method-list))
730 (eieio--generic-call-arglst newargs)
731 (fcn (car next))
732 )
733 (apply fcn newargs)) )))
734
735 (defgeneric no-applicable-method (object method &rest args)
736 "Called if there are no implementations for OBJECT in METHOD.")
737
738 (defmethod no-applicable-method (object method &rest _args)
739 "Called if there are no implementations for OBJECT in METHOD.
740 OBJECT is the object which has no method implementation.
741 ARGS are the arguments that were passed to METHOD.
742
743 Implement this for a class to block this signal. The return
744 value becomes the return value of the original method call."
745 (signal 'no-method-definition (list method object)))
746
747 (defgeneric no-next-method (object &rest args)
748 "Called from `call-next-method' when no additional methods are available.")
749
750 (defmethod no-next-method (object &rest args)
751 "Called from `call-next-method' when no additional methods are available.
752 OBJECT is othe object being called on `call-next-method'.
753 ARGS are the arguments it is called by.
754 This method signals `no-next-method' by default. Override this
755 method to not throw an error, and its return value becomes the
756 return value of `call-next-method'."
757 (signal 'no-next-method (list object args)))
758
759 (add-hook 'help-fns-describe-function-functions 'eieio--help-generic)
760 (defun eieio--help-generic (generic)
761 "Describe GENERIC if it is a generic function."
762 (when (and (symbolp generic) (generic-p generic))
763 (save-excursion
764 (goto-char (point-min))
765 (when (re-search-forward " in `.+'.$" nil t)
766 (replace-match ".")))
767 (save-excursion
768 (insert "\n\nThis is a generic function"
769 (cond
770 ((and (eieio--generic-primary-only-p generic)
771 (eieio--generic-primary-only-one-p generic))
772 " with only one primary method")
773 ((eieio--generic-primary-only-p generic)
774 " with only primary methods")
775 (t ""))
776 ".\n\n")
777 (insert (propertize "Implementations:\n\n" 'face 'bold))
778 (let ((i 4)
779 (prefix [ ":STATIC" ":BEFORE" ":PRIMARY" ":AFTER" ] ))
780 ;; Loop over fanciful generics
781 (while (< i 7)
782 (let ((gm (aref (get generic 'eieio-method-tree) i)))
783 (when gm
784 (insert "Generic "
785 (aref prefix (- i 3))
786 "\n"
787 (or (nth 2 gm) "Undocumented")
788 "\n\n")))
789 (setq i (1+ i)))
790 (setq i 0)
791 ;; Loop over defined class-specific methods
792 (while (< i 4)
793 (let* ((gm (reverse (aref (get generic 'eieio-method-tree) i)))
794 cname location)
795 (while gm
796 (setq cname (caar gm))
797 (insert "`")
798 (help-insert-xref-button (symbol-name cname)
799 'help-variable cname)
800 (insert "' " (aref prefix i) " ")
801 ;; argument list
802 (let* ((func (cdr (car gm)))
803 (arglst (help-function-arglist func)))
804 (prin1 arglst (current-buffer)))
805 (insert "\n"
806 (or (documentation (cdr (car gm)))
807 "Undocumented"))
808 ;; Print file location if available
809 (when (and (setq location (get generic 'method-locations))
810 (setq location (assoc cname location)))
811 (setq location (cadr location))
812 (insert "\n\nDefined in `")
813 (help-insert-xref-button
814 (file-name-nondirectory location)
815 'eieio-method-def cname generic location)
816 (insert "'\n"))
817 (setq gm (cdr gm))
818 (insert "\n")))
819 (setq i (1+ i)))))))
820
821 ;;; Obsolete backward compatibility functions.
822 ;; Needed to run byte-code compiled with the EIEIO of Emacs-23.
823
824 (defun eieio-defmethod (method args)
825 "Obsolete work part of an old version of the `defmethod' macro."
826 (let ((key nil) (body nil) (firstarg nil) (argfix nil) (argclass nil) loopa)
827 ;; find optional keys
828 (setq key
829 (cond ((memq (car args) '(:BEFORE :before))
830 (setq args (cdr args))
831 eieio--method-before)
832 ((memq (car args) '(:AFTER :after))
833 (setq args (cdr args))
834 eieio--method-after)
835 ((memq (car args) '(:STATIC :static))
836 (setq args (cdr args))
837 eieio--method-static)
838 ((memq (car args) '(:PRIMARY :primary))
839 (setq args (cdr args))
840 eieio--method-primary)
841 ;; Primary key.
842 (t eieio--method-primary)))
843 ;; Get body, and fix contents of args to be the arguments of the fn.
844 (setq body (cdr args)
845 args (car args))
846 (setq loopa args)
847 ;; Create a fixed version of the arguments.
848 (while loopa
849 (setq argfix (cons (if (listp (car loopa)) (car (car loopa)) (car loopa))
850 argfix))
851 (setq loopa (cdr loopa)))
852 ;; Make sure there is a generic.
853 (eieio-defgeneric
854 method
855 (if (stringp (car body))
856 (car body) (format "Generically created method `%s'." method)))
857 ;; create symbol for property to bind to. If the first arg is of
858 ;; the form (varname vartype) and `vartype' is a class, then
859 ;; that class will be the type symbol. If not, then it will fall
860 ;; under the type `primary' which is a non-specific calling of the
861 ;; function.
862 (setq firstarg (car args))
863 (if (listp firstarg)
864 (progn
865 (setq argclass (nth 1 firstarg))
866 (if (not (class-p argclass))
867 (error "Unknown class type %s in method parameters"
868 (nth 1 firstarg))))
869 ;; Generics are higher.
870 (setq key (eieio--specialized-key-to-generic-key key)))
871 ;; Put this lambda into the symbol so we can find it.
872 (if (byte-code-function-p (car-safe body))
873 (eieio--mt-add method (car-safe body) key argclass)
874 (eieio--mt-add method (append (list 'lambda (reverse argfix)) body)
875 key argclass))
876 )
877
878 (eieio--method-optimize-primary method)
879
880 method)
881 (make-obsolete 'eieio-defmethod 'eieio--defmethod "24.1")
882
883 (defun eieio-defgeneric (method doc-string)
884 "Obsolete work part of an old version of the `defgeneric' macro."
885 (if (and (fboundp method) (not (generic-p method))
886 (or (byte-code-function-p (symbol-function method))
887 (not (eq 'autoload (car (symbol-function method)))))
888 )
889 (error "You cannot create a generic/method over an existing symbol: %s"
890 method))
891 ;; Don't do this over and over.
892 (unless (fboundp 'method)
893 ;; This defun tells emacs where the first definition of this
894 ;; method is defined.
895 `(defun ,method nil)
896 ;; Make sure the method tables are installed.
897 (eieio--mt-install method)
898 ;; Apply the actual body of this function.
899 (put method 'function-documentation doc-string)
900 (fset method (eieio--defgeneric-form method))
901 ;; Return the method
902 'method))
903 (make-obsolete 'eieio-defgeneric nil "24.1")
904
905 (provide 'eieio-generic)
906
907 ;;; eieio-generic.el ends here