1 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; This software is derived from software originally released by Xerox
5 ;;;; Corporation. Copyright and release statements follow. Later modifications
6 ;;;; to the software are in the public domain and are provided with
7 ;;;; absolutely no warranty. See the COPYING and CREDITS files for more
10 ;;;; copyright information from original PCL sources:
12 ;;;; Copyright (c) 1985, 1986, 1987, 1988, 1989, 1990 Xerox Corporation.
13 ;;;; All rights reserved.
15 ;;;; Use and copying of this software and preparation of derivative works based
16 ;;;; upon this software are permitted. Any distribution of this software or
17 ;;;; derivative works must comply with all applicable United States export
20 ;;;; This software is made available AS IS, and Xerox Corporation makes no
21 ;;;; warranty about the software, its performance or its conformity to any
29 ;;; Methods themselves are simple inanimate objects. Most properties of
30 ;;; methods are immutable, methods cannot be reinitialized. The following
31 ;;; properties of methods can be changed:
32 ;;; METHOD-GENERIC-FUNCTION
33 ;;; METHOD-FUNCTION ??
35 (defmethod method-function ((method standard-method
))
36 (or (slot-value method
'function
)
37 (let ((fmf (slot-value method
'fast-function
)))
38 (unless fmf
; The :BEFORE SHARED-INITIALIZE method prevents this.
39 (error "~S doesn't seem to have a METHOD-FUNCTION." method
))
40 (setf (slot-value method
'function
)
41 (method-function-from-fast-function fmf
)))))
43 (defmethod accessor-method-class ((method standard-accessor-method
))
44 (car (slot-value method
'specializers
)))
46 (defmethod accessor-method-class ((method standard-writer-method
))
47 (cadr (slot-value method
'specializers
)))
51 ;;; Error checking is done in before methods. Because of the simplicity of
52 ;;; standard method objects the standard primary method can fill the slots.
54 ;;; Methods are not reinitializable.
56 (defmethod reinitialize-instance ((method standard-method
) &rest initargs
)
57 (declare (ignore initargs
))
58 (error "An attempt was made to reinitialize the method ~S.~%~
59 Method objects cannot be reinitialized."
62 (defmethod legal-documentation-p ((object standard-method
) x
)
63 (if (or (null x
) (stringp x
))
67 (defmethod legal-lambda-list-p ((object standard-method
) x
)
71 (defmethod legal-method-function-p ((object standard-method
) x
)
76 (defmethod legal-qualifiers-p ((object standard-method
) x
)
77 (flet ((improper-list ()
78 (return-from legal-qualifiers-p
"Is not a proper list.")))
79 (dolist-carefully (q x improper-list
)
80 (let ((ok (legal-qualifier-p object q
)))
82 (return-from legal-qualifiers-p
83 (format nil
"Contains ~S which ~A" q ok
)))))
86 (defmethod legal-qualifier-p ((object standard-method
) x
)
89 "is not a non-null atom"))
91 (defmethod legal-slot-name-p ((object standard-method
) x
)
92 (cond ((not (symbolp x
)) "is not a symbol and so cannot be bound")
93 ((keywordp x
) "is a keyword and so cannot be bound")
94 ((memq x
'(t nil
)) "cannot be bound")
95 ((constantp x
) "is a constant and so cannot be bound")
98 (defmethod legal-specializers-p ((object standard-method
) x
)
99 (flet ((improper-list ()
100 (return-from legal-specializers-p
"Is not a proper list.")))
101 (dolist-carefully (s x improper-list
)
102 (let ((ok (legal-specializer-p object s
)))
104 (return-from legal-specializers-p
105 (format nil
"Contains ~S which ~A" s ok
)))))
108 (defvar *allow-experimental-specializers-p
* nil
)
110 (defmethod legal-specializer-p ((object standard-method
) x
)
111 (if (if *allow-experimental-specializers-p
*
114 (eql-specializer-p x
)))
116 "is neither a class object nor an EQL specializer"))
118 (defmethod shared-initialize :before
((method standard-method
)
126 (declare (ignore slot-names
))
127 (flet ((lose (initarg value string
)
128 (error "when initializing the method ~S:~%~
129 The ~S initialization argument was: ~S.~%~
131 method initarg value string
)))
132 (let ((check-qualifiers (legal-qualifiers-p method qualifiers
))
133 (check-lambda-list (legal-lambda-list-p method lambda-list
))
134 (check-specializers (legal-specializers-p method specializers
))
135 (check-fun (legal-method-function-p method
138 (check-documentation (legal-documentation-p method documentation
)))
139 (unless (eq check-qualifiers t
)
140 (lose :qualifiers qualifiers check-qualifiers
))
141 (unless (eq check-lambda-list t
)
142 (lose :lambda-list lambda-list check-lambda-list
))
143 (unless (eq check-specializers t
)
144 (lose :specializers specializers check-specializers
))
145 (unless (eq check-fun t
)
146 (lose :function function check-fun
))
147 (unless (eq check-documentation t
)
148 (lose :documentation documentation check-documentation
)))))
150 (defmethod shared-initialize :before
((method standard-accessor-method
)
152 &key slot-name slot-definition
)
153 (declare (ignore slot-names
))
154 (unless slot-definition
155 (let ((legalp (legal-slot-name-p method slot-name
)))
156 ;; FIXME: nasty convention; should be renamed to ILLEGAL-SLOT-NAME-P and
157 ;; ILLEGALP, and the convention redone to be less twisty
158 (unless (eq legalp t
)
159 (error "The value of the :SLOT-NAME initarg ~A." legalp
)))))
161 (defmethod shared-initialize :after
((method standard-method
) slot-names
163 &key qualifiers method-spec plist
)
164 (declare (ignore slot-names method-spec plist
))
165 (initialize-method-function initargs nil method
)
166 (setf (plist-value method
'qualifiers
) qualifiers
)
168 (setf (slot-value method
'closure-generator
)
169 (method-function-closure-generator (slot-value method
'function
))))
171 (defmethod shared-initialize :after
((method standard-accessor-method
)
174 (declare (ignore slot-names
))
175 (with-slots (slot-name slot-definition
)
177 (unless slot-definition
178 (let ((class (accessor-method-class method
)))
179 (when (slot-class-p class
)
180 (setq slot-definition
(find slot-name
(class-direct-slots class
)
181 :key
#'slot-definition-name
)))))
182 (when (and slot-definition
(null slot-name
))
183 (setq slot-name
(slot-definition-name slot-definition
)))))
185 (defmethod method-qualifiers ((method standard-method
))
186 (plist-value method
'qualifiers
))
188 (defvar *the-class-generic-function
*
189 (find-class 'generic-function
))
190 (defvar *the-class-standard-generic-function
*
191 (find-class 'standard-generic-function
))
193 (defmethod shared-initialize :before
194 ((generic-function standard-generic-function
)
196 &key
(name nil namep
)
197 (lambda-list () lambda-list-p
)
198 argument-precedence-order
201 (method-class nil method-class-supplied-p
)
202 (method-combination nil method-combination-supplied-p
))
203 (declare (ignore slot-names
204 declarations argument-precedence-order documentation
205 lambda-list lambda-list-p
))
208 (set-fun-name generic-function name
))
210 (flet ((initarg-error (initarg value string
)
211 (error "when initializing the generic function ~S:~%~
212 The ~S initialization argument was: ~A.~%~
214 generic-function initarg value string
)))
215 (cond (method-class-supplied-p
216 (when (symbolp method-class
)
217 (setq method-class
(find-class method-class
)))
218 (unless (and (classp method-class
)
219 (*subtypep
(class-eq-specializer method-class
)
221 (initarg-error :method-class
223 "a subclass of the class METHOD"))
224 (setf (slot-value generic-function
'method-class
) method-class
))
225 ((slot-boundp generic-function
'method-class
))
227 (initarg-error :method-class
229 "a subclass of the class METHOD")))
230 (cond (method-combination-supplied-p
231 (unless (method-combination-p method-combination
)
232 (initarg-error :method-combination
234 "a method combination object")))
235 ((slot-boundp generic-function
'method-combination
))
237 (initarg-error :method-combination
239 "a method combination object")))))
242 (defmethod reinitialize-instance ((generic-function standard-generic-function
)
246 argument-precedence-order
251 (declare (ignore documentation declarations argument-precedence-order
252 lambda-list name method-class method-combination
))
253 (macrolet ((add-initarg (check name slot-name
)
255 (push (slot-value generic-function
,slot-name
) initargs
)
256 (push ,name initargs
))))
257 ; (add-initarg name :name 'name)
258 ; (add-initarg lambda-list :lambda-list 'lambda-list)
259 ; (add-initarg argument-precedence-order
260 ; :argument-precedence-order
261 ; 'argument-precedence-order)
262 ; (add-initarg declarations :declarations 'declarations)
263 ; (add-initarg documentation :documentation 'documentation)
264 ; (add-initarg method-class :method-class 'method-class)
265 ; (add-initarg method-combination :method-combination 'method-combination)
266 (apply #'call-next-method generic-function initargs
)))
269 ;;; These three are scheduled for demolition.
271 (defmethod remove-named-method (generic-function-name argument-specifiers
273 (let ((generic-function ())
275 (cond ((or (null (fboundp generic-function-name
))
276 (not (generic-function-p
277 (setq generic-function
278 (fdefinition generic-function-name
)))))
279 (error "~S does not name a generic function."
280 generic-function-name
))
281 ((null (setq method
(get-method generic-function
286 (error "There is no method for the generic function ~S~%~
287 which matches the ARGUMENT-SPECIFIERS ~S."
289 argument-specifiers
))
291 (remove-method generic-function method
)))))
293 (defun real-add-named-method (generic-function-name
297 &rest other-initargs
)
298 (unless (and (fboundp generic-function-name
)
299 (typep (fdefinition generic-function-name
) 'generic-function
))
300 (style-warn "implicitly creating new generic function ~S"
301 generic-function-name
))
302 ;; XXX What about changing the class of the generic function if
303 ;; there is one? Whose job is that, anyway? Do we need something
304 ;; kind of like CLASS-FOR-REDEFINITION?
305 (let* ((generic-function
306 (ensure-generic-function generic-function-name
))
307 (specs (parse-specializers specializers
))
308 (proto (method-prototype-for-gf generic-function-name
))
309 (new (apply #'make-instance
(class-of proto
)
310 :qualifiers qualifiers
312 :lambda-list lambda-list
314 (add-method generic-function new
)))
316 (defun real-get-method (generic-function qualifiers specializers
317 &optional
(errorp t
))
319 (dolist (method (generic-function-methods generic-function
))
320 (let ((mspecializers (method-specializers method
)))
321 (when (and (equal qualifiers
(method-qualifiers method
))
322 (= (length specializers
) (length mspecializers
))
323 (every #'same-specializer-p specializers
324 (method-specializers method
)))
329 (error "no method on ~S with qualifiers ~:S and specializers ~:S"
330 generic-function qualifiers specializers
)))))
332 (defmethod find-method ((generic-function standard-generic-function
)
333 qualifiers specializers
&optional
(errorp t
))
334 (real-get-method generic-function qualifiers
335 (parse-specializers specializers
) errorp
))
337 ;;; Compute various information about a generic-function's arglist by looking
338 ;;; at the argument lists of the methods. The hair for trying not to use
339 ;;; &REST arguments lives here.
340 ;;; The values returned are:
341 ;;; number-of-required-arguments
342 ;;; the number of required arguments to this generic-function's
343 ;;; discriminating function
345 ;;; whether or not this generic-function's discriminating
346 ;;; function takes an &rest argument.
347 ;;; specialized-argument-positions
348 ;;; a list of the positions of the arguments this generic-function
349 ;;; specializes (e.g. for a classical generic-function this is the
351 (defmethod compute-discriminating-function-arglist-info
352 ((generic-function standard-generic-function
))
353 ;;(declare (values number-of-required-arguments &rest-argument-p
354 ;; specialized-argument-postions))
355 (let ((number-required nil
)
357 (specialized-positions ())
358 (methods (generic-function-methods generic-function
)))
359 (dolist (method methods
)
360 (multiple-value-setq (number-required restp specialized-positions
)
361 (compute-discriminating-function-arglist-info-internal
362 generic-function method number-required restp specialized-positions
)))
363 (values number-required restp
(sort specialized-positions
#'<))))
365 (defun compute-discriminating-function-arglist-info-internal
366 (generic-function method number-of-requireds restp
367 specialized-argument-positions
)
368 (declare (ignore generic-function
)
369 (type (or null fixnum
) number-of-requireds
))
371 (declare (fixnum requireds
))
372 ;; Go through this methods arguments seeing how many are required,
373 ;; and whether there is an &rest argument.
374 (dolist (arg (method-lambda-list method
))
375 (cond ((eq arg
'&aux
) (return))
376 ((memq arg
'(&optional
&rest
&key
))
377 (return (setq restp t
)))
378 ((memq arg lambda-list-keywords
))
379 (t (incf requireds
))))
380 ;; Now go through this method's type specifiers to see which
381 ;; argument positions are type specified. Treat T specially
382 ;; in the usual sort of way. For efficiency don't bother to
383 ;; keep specialized-argument-positions sorted, rather depend
384 ;; on our caller to do that.
386 (dolist (type-spec (method-specializers method
))
387 (unless (eq type-spec
*the-class-t
*)
388 (pushnew pos specialized-argument-positions
))
390 ;; Finally merge the values for this method into the values
391 ;; for the exisiting methods and return them. Note that if
392 ;; num-of-requireds is NIL it means this is the first method
393 ;; and we depend on that.
394 (values (min (or number-of-requireds requireds
) requireds
)
396 (and number-of-requireds
(/= number-of-requireds requireds
)))
397 specialized-argument-positions
)))
399 (defun make-discriminating-function-arglist (number-required-arguments restp
)
400 (nconc (let ((args nil
))
401 (dotimes (i number-required-arguments
)
402 (push (intern (format nil
"Discriminating Function Arg ~D" i
))
406 `(&rest
,(intern "Discriminating Function &rest Arg")))))
408 (defmethod generic-function-argument-precedence-order
409 ((gf standard-generic-function
))
410 (aver (eq *boot-state
* 'complete
))
411 (loop with arg-info
= (gf-arg-info gf
)
412 with lambda-list
= (arg-info-lambda-list arg-info
)
413 for argument-position in
(arg-info-precedence arg-info
)
414 collect
(nth argument-position lambda-list
)))
416 (defmethod generic-function-lambda-list ((gf generic-function
))
419 (defmethod gf-fast-method-function-p ((gf standard-generic-function
))
420 (gf-info-fast-mf-p (slot-value gf
'arg-info
)))
422 (defmethod initialize-instance :after
((gf standard-generic-function
)
423 &key
(lambda-list nil lambda-list-p
)
424 argument-precedence-order
)
425 (with-slots (arg-info)
429 :lambda-list lambda-list
430 :argument-precedence-order argument-precedence-order
)
432 (when (arg-info-valid-p arg-info
)
435 (defmethod reinitialize-instance :after
((gf standard-generic-function
)
437 &key
(lambda-list nil lambda-list-p
)
438 (argument-precedence-order
439 nil argument-precedence-order-p
))
440 (with-slots (arg-info)
443 (if argument-precedence-order-p
445 :lambda-list lambda-list
446 :argument-precedence-order argument-precedence-order
)
448 :lambda-list lambda-list
))
450 (when (and (arg-info-valid-p arg-info
)
452 (or lambda-list-p
(cddr args
)))
455 (declaim (special *lazy-dfun-compute-p
*))
457 (defun set-methods (gf methods
)
458 (setf (generic-function-methods gf
) nil
)
459 (loop (when (null methods
) (return gf
))
460 (real-add-method gf
(pop methods
) methods
)))
462 (defun real-add-method (generic-function method
&optional skip-dfun-update-p
)
463 (when (method-generic-function method
)
464 (error "The method ~S is already part of the generic~@
465 function ~S. It can't be added to another generic~@
466 function until it is removed from the first one."
467 method
(method-generic-function method
)))
468 (flet ((similar-lambda-lists-p (method-a method-b
)
469 (multiple-value-bind (a-nreq a-nopt a-keyp a-restp
)
470 (analyze-lambda-list (method-lambda-list method-a
))
471 (multiple-value-bind (b-nreq b-nopt b-keyp b-restp
)
472 (analyze-lambda-list (method-lambda-list method-b
))
473 (and (= a-nreq b-nreq
)
475 (eq (or a-keyp a-restp
)
476 (or b-keyp b-restp
)))))))
477 (let* ((name (generic-function-name generic-function
))
478 (qualifiers (method-qualifiers method
))
479 (specializers (method-specializers method
))
480 (existing (get-method generic-function
485 ;; If there is already a method like this one then we must get
486 ;; rid of it before proceeding. Note that we call the generic
487 ;; function REMOVE-METHOD to remove it rather than doing it in
488 ;; some internal way.
489 (when (and existing
(similar-lambda-lists-p existing method
))
490 (remove-method generic-function existing
))
492 (setf (method-generic-function method
) generic-function
)
493 (pushnew method
(generic-function-methods generic-function
))
494 (dolist (specializer specializers
)
495 (add-direct-method specializer method
))
497 ;; KLUDGE: SET-ARG-INFO contains the error-detecting logic for
498 ;; detecting attempts to add methods with incongruent lambda
499 ;; lists. However, according to Gerd Moellmann on cmucl-imp,
500 ;; it also depends on the new method already having been added
501 ;; to the generic function. Therefore, we need to remove it
503 (let ((remove-again-p t
))
506 (set-arg-info generic-function
:new-method method
)
507 (setq remove-again-p nil
))
509 (remove-method generic-function method
))))
510 (unless skip-dfun-update-p
511 (update-ctors 'add-method
512 :generic-function generic-function
514 (update-dfun generic-function
))
517 (defun real-remove-method (generic-function method
)
518 (when (eq generic-function
(method-generic-function method
))
519 (let* ((name (generic-function-name generic-function
))
520 (specializers (method-specializers method
))
521 (methods (generic-function-methods generic-function
))
522 (new-methods (remove method methods
)))
523 (setf (method-generic-function method
) nil
)
524 (setf (generic-function-methods generic-function
) new-methods
)
525 (dolist (specializer (method-specializers method
))
526 (remove-direct-method specializer method
))
527 (set-arg-info generic-function
)
528 (update-ctors 'remove-method
529 :generic-function generic-function
531 (update-dfun generic-function
)))
534 (defun compute-applicable-methods-function (generic-function arguments
)
535 (values (compute-applicable-methods-using-types
537 (types-from-args generic-function arguments
'eql
))))
539 (defmethod compute-applicable-methods
540 ((generic-function generic-function
) arguments
)
541 (values (compute-applicable-methods-using-types
543 (types-from-args generic-function arguments
'eql
))))
545 (defmethod compute-applicable-methods-using-classes
546 ((generic-function generic-function
) classes
)
547 (compute-applicable-methods-using-types
549 (types-from-args generic-function classes
'class-eq
)))
551 (defun proclaim-incompatible-superclasses (classes)
552 (setq classes
(mapcar (lambda (class)
557 (dolist (class classes
)
558 (dolist (other-class classes
)
559 (unless (eq class other-class
)
560 (pushnew other-class
(class-incompatible-superclass-list class
))))))
562 (defun superclasses-compatible-p (class1 class2
)
563 (let ((cpl1 (cpl-or-nil class1
))
564 (cpl2 (cpl-or-nil class2
)))
566 (dolist (ic (class-incompatible-superclass-list sc1
))
568 (return-from superclasses-compatible-p nil
))))))
571 #'proclaim-incompatible-superclasses
572 '(;; superclass class
573 (built-in-class std-class structure-class
) ; direct subclasses of pcl-class
574 (standard-class funcallable-standard-class
)
575 ;; superclass metaobject
576 (class eql-specializer class-eq-specializer method method-combination
577 generic-function slot-definition
)
578 ;; metaclass built-in-class
579 (number sequence character
; direct subclasses of t, but not array
580 standard-object structure-object
) ; or symbol
581 (number array character symbol
; direct subclasses of t, but not
582 standard-object structure-object
) ; sequence
583 (complex float rational
) ; direct subclasses of number
584 (integer ratio
) ; direct subclasses of rational
585 (list vector
) ; direct subclasses of sequence
586 (cons null
) ; direct subclasses of list
587 (string bit-vector
) ; direct subclasses of vector
590 (defmethod same-specializer-p ((specl1 specializer
) (specl2 specializer
))
593 (defmethod same-specializer-p ((specl1 class
) (specl2 class
))
596 (defmethod specializer-class ((specializer class
))
599 (defmethod same-specializer-p ((specl1 class-eq-specializer
)
600 (specl2 class-eq-specializer
))
601 (eq (specializer-class specl1
) (specializer-class specl2
)))
603 (defmethod same-specializer-p ((specl1 eql-specializer
)
604 (specl2 eql-specializer
))
605 (eq (specializer-object specl1
) (specializer-object specl2
)))
607 (defmethod specializer-class ((specializer eql-specializer
))
608 (class-of (slot-value specializer
'object
)))
610 (defvar *in-gf-arg-info-p
* nil
)
611 (setf (gdefinition 'arg-info-reader
)
612 (let ((mf (initialize-method-function
613 (make-internal-reader-method-function
614 'standard-generic-function
'arg-info
)
616 (lambda (&rest args
) (funcall mf args nil
))))
619 (defun error-need-at-least-n-args (function n
)
620 (error "~@<The function ~2I~_~S ~I~_requires at least ~W argument~:P.~:>"
624 (defun types-from-args (generic-function arguments
&optional type-modifier
)
625 (multiple-value-bind (nreq applyp metatypes nkeys arg-info
)
626 (get-generic-fun-info generic-function
)
627 (declare (ignore applyp metatypes nkeys
))
628 (let ((types-rev nil
))
629 (dotimes-fixnum (i nreq
)
632 (error-need-at-least-n-args (generic-function-name generic-function
)
634 (let ((arg (pop arguments
)))
635 (push (if type-modifier
`(,type-modifier
,arg
) arg
) types-rev
)))
636 (values (nreverse types-rev
) arg-info
))))
638 (defun get-wrappers-from-classes (nkeys wrappers classes metatypes
)
639 (let* ((w wrappers
) (w-tail w
) (mt-tail metatypes
))
640 (dolist (class (if (listp classes
) classes
(list classes
)))
641 (unless (eq t
(car mt-tail
))
642 (let ((c-w (class-wrapper class
)))
643 (unless c-w
(return-from get-wrappers-from-classes nil
))
646 (setf (car w-tail
) c-w
647 w-tail
(cdr w-tail
)))))
648 (setq mt-tail
(cdr mt-tail
)))
651 (defun sdfun-for-caching (gf classes
)
652 (let ((types (mapcar #'class-eq-type classes
)))
653 (multiple-value-bind (methods all-applicable-and-sorted-p
)
654 (compute-applicable-methods-using-types gf types
)
655 (function-funcall (get-secondary-dispatch-function1
656 gf methods types nil t all-applicable-and-sorted-p
)
657 nil
(mapcar #'class-wrapper classes
)))))
659 (defun value-for-caching (gf classes
)
660 (let ((methods (compute-applicable-methods-using-types
661 gf
(mapcar #'class-eq-type classes
))))
662 (method-function-get (or (method-fast-function (car methods
))
663 (method-function (car methods
)))
666 (defun default-secondary-dispatch-function (generic-function)
668 (let ((methods (compute-applicable-methods generic-function args
)))
670 (let ((emf (get-effective-method-function generic-function
672 (invoke-emf emf args
))
673 (apply #'no-applicable-method generic-function args
)))))
676 (loop (when (atom x
) (return (eq x y
)))
677 (when (atom y
) (return nil
))
678 (unless (eq (car x
) (car y
)) (return nil
))
679 (setq x
(cdr x
) y
(cdr y
))))
681 (defvar *std-cam-methods
* nil
)
683 (defun compute-applicable-methods-emf (generic-function)
684 (if (eq *boot-state
* 'complete
)
685 (let* ((cam (gdefinition 'compute-applicable-methods
))
686 (cam-methods (compute-applicable-methods-using-types
687 cam
(list `(eql ,generic-function
) t
))))
688 (values (get-effective-method-function cam cam-methods
)
690 (or *std-cam-methods
*
691 (setq *std-cam-methods
*
692 (compute-applicable-methods-using-types
693 cam
(list `(eql ,cam
) t
)))))))
694 (values #'compute-applicable-methods-function t
)))
696 (defun compute-applicable-methods-emf-std-p (gf)
697 (gf-info-c-a-m-emf-std-p (gf-arg-info gf
)))
699 (defvar *old-c-a-m-gf-methods
* nil
)
701 (defun update-all-c-a-m-gf-info (c-a-m-gf)
702 (let ((methods (generic-function-methods c-a-m-gf
)))
703 (if (and *old-c-a-m-gf-methods
*
704 (every (lambda (old-method)
705 (member old-method methods
))
706 *old-c-a-m-gf-methods
*))
707 (let ((gfs-to-do nil
)
708 (gf-classes-to-do nil
))
709 (dolist (method methods
)
710 (unless (member method
*old-c-a-m-gf-methods
*)
711 (let ((specl (car (method-specializers method
))))
712 (if (eql-specializer-p specl
)
713 (pushnew (specializer-object specl
) gfs-to-do
)
714 (pushnew (specializer-class specl
) gf-classes-to-do
)))))
715 (map-all-generic-functions
717 (when (or (member gf gfs-to-do
)
718 (dolist (class gf-classes-to-do nil
)
720 (class-precedence-list (class-of gf
)))))
721 (update-c-a-m-gf-info gf
)))))
722 (map-all-generic-functions #'update-c-a-m-gf-info
))
723 (setq *old-c-a-m-gf-methods
* methods
)))
725 (defun update-gf-info (gf)
726 (update-c-a-m-gf-info gf
)
727 (update-gf-simple-accessor-type gf
))
729 (defun update-c-a-m-gf-info (gf)
730 (unless (early-gf-p gf
)
731 (multiple-value-bind (c-a-m-emf std-p
)
732 (compute-applicable-methods-emf gf
)
733 (let ((arg-info (gf-arg-info gf
)))
734 (setf (gf-info-static-c-a-m-emf arg-info
) c-a-m-emf
)
735 (setf (gf-info-c-a-m-emf-std-p arg-info
) std-p
)))))
737 (defun update-gf-simple-accessor-type (gf)
738 (let ((arg-info (gf-arg-info gf
)))
739 (setf (gf-info-simple-accessor-type arg-info
)
740 (let* ((methods (generic-function-methods gf
))
741 (class (and methods
(class-of (car methods
))))
744 *the-class-standard-reader-method
*)
747 *the-class-standard-writer-method
*)
750 *the-class-standard-boundp-method
*)
752 (when (and (gf-info-c-a-m-emf-std-p arg-info
)
754 (dolist (method (cdr methods
) t
)
755 (unless (eq class
(class-of method
)) (return nil
)))
756 (eq (generic-function-method-combination gf
)
757 *standard-method-combination
*))
761 ;;; CMUCL (Gerd's PCL, 2002-04-25) comment:
763 ;;; Return two values. First value is a function to be stored in
764 ;;; effective slot definition SLOTD for reading it with
765 ;;; SLOT-VALUE-USING-CLASS, setting it with (SETF
766 ;;; SLOT-VALUE-USING-CLASS) or testing it with
767 ;;; SLOT-BOUNDP-USING-CLASS. GF is one of these generic functions,
768 ;;; TYPE is one of the symbols READER, WRITER, BOUNDP. CLASS is
771 ;;; Second value is true if the function returned is one of the
772 ;;; optimized standard functions for the purpose, which are used
773 ;;; when only standard methods are applicable.
775 ;;; FIXME: Change all these wacky function names to something sane.
776 (defun get-accessor-method-function (gf type class slotd
)
777 (let* ((std-method (standard-svuc-method type
))
778 (str-method (structure-svuc-method type
))
779 (types1 `((eql ,class
) (class-eq ,class
) (eql ,slotd
)))
780 (types (if (eq type
'writer
) `(t ,@types1
) types1
))
781 (methods (compute-applicable-methods-using-types gf types
))
782 (std-p (null (cdr methods
))))
785 (get-optimized-std-accessor-method-function class slotd type
)
786 (let* ((optimized-std-fun
787 (get-optimized-std-slot-value-using-class-method-function
790 `((,(car (or (member std-method methods
)
791 (member str-method methods
)
793 'get-accessor-method-function
)))
794 ,optimized-std-fun
)))
796 (let ((wrappers (list (wrapper-of class
)
797 (class-wrapper class
)
798 (wrapper-of slotd
))))
799 (if (eq type
'writer
)
800 (cons (class-wrapper *the-class-t
*) wrappers
)
802 (sdfun (get-secondary-dispatch-function
803 gf methods types method-alist wrappers
)))
804 (get-accessor-from-svuc-method-function class slotd sdfun type
)))
807 ;;; used by OPTIMIZE-SLOT-VALUE-BY-CLASS-P (vector.lisp)
808 (defun update-slot-value-gf-info (gf type
)
810 (update-std-or-str-methods gf type
))
811 (when (and (standard-svuc-method type
) (structure-svuc-method type
))
812 (flet ((update-class (class)
813 (when (class-finalized-p class
)
814 (dolist (slotd (class-slots class
))
815 (compute-slot-accessor-info slotd type gf
)))))
817 (update-class *new-class
*)
818 (map-all-classes #'update-class
'slot-object
)))))
820 (defvar *standard-slot-value-using-class-method
* nil
)
821 (defvar *standard-setf-slot-value-using-class-method
* nil
)
822 (defvar *standard-slot-boundp-using-class-method
* nil
)
823 (defvar *condition-slot-value-using-class-method
* nil
)
824 (defvar *condition-setf-slot-value-using-class-method
* nil
)
825 (defvar *condition-slot-boundp-using-class-method
* nil
)
826 (defvar *structure-slot-value-using-class-method
* nil
)
827 (defvar *structure-setf-slot-value-using-class-method
* nil
)
828 (defvar *structure-slot-boundp-using-class-method
* nil
)
830 (defun standard-svuc-method (type)
832 (reader *standard-slot-value-using-class-method
*)
833 (writer *standard-setf-slot-value-using-class-method
*)
834 (boundp *standard-slot-boundp-using-class-method
*)))
836 (defun set-standard-svuc-method (type method
)
838 (reader (setq *standard-slot-value-using-class-method
* method
))
839 (writer (setq *standard-setf-slot-value-using-class-method
* method
))
840 (boundp (setq *standard-slot-boundp-using-class-method
* method
))))
842 (defun condition-svuc-method (type)
844 (reader *condition-slot-value-using-class-method
*)
845 (writer *condition-setf-slot-value-using-class-method
*)
846 (boundp *condition-slot-boundp-using-class-method
*)))
848 (defun set-condition-svuc-method (type method
)
850 (reader (setq *condition-slot-value-using-class-method
* method
))
851 (writer (setq *condition-setf-slot-value-using-class-method
* method
))
852 (boundp (setq *condition-slot-boundp-using-class-method
* method
))))
854 (defun structure-svuc-method (type)
856 (reader *structure-slot-value-using-class-method
*)
857 (writer *structure-setf-slot-value-using-class-method
*)
858 (boundp *structure-slot-boundp-using-class-method
*)))
860 (defun set-structure-svuc-method (type method
)
862 (reader (setq *structure-slot-value-using-class-method
* method
))
863 (writer (setq *structure-setf-slot-value-using-class-method
* method
))
864 (boundp (setq *structure-slot-boundp-using-class-method
* method
))))
866 (defun update-std-or-str-methods (gf type
)
867 (dolist (method (generic-function-methods gf
))
868 (let ((specls (method-specializers method
)))
869 (when (and (or (not (eq type
'writer
))
870 (eq (pop specls
) *the-class-t
*))
871 (every #'classp specls
))
872 (cond ((and (eq (class-name (car specls
)) 'std-class
)
873 (eq (class-name (cadr specls
)) 'std-object
)
874 (eq (class-name (caddr specls
))
875 'standard-effective-slot-definition
))
876 (set-standard-svuc-method type method
))
877 ((and (eq (class-name (car specls
)) 'condition-class
)
878 (eq (class-name (cadr specls
)) 'condition
)
879 (eq (class-name (caddr specls
))
880 'condition-effective-slot-definition
))
881 (set-condition-svuc-method type method
))
882 ((and (eq (class-name (car specls
)) 'structure-class
)
883 (eq (class-name (cadr specls
)) 'structure-object
)
884 (eq (class-name (caddr specls
))
885 'structure-effective-slot-definition
))
886 (set-structure-svuc-method type method
)))))))
888 (defun mec-all-classes-internal (spec precompute-p
)
889 (cons (specializer-class spec
)
892 (not (or (eq spec
*the-class-t
*)
893 (eq spec
*the-class-slot-object
*)
894 (eq spec
*the-class-std-object
*)
895 (eq spec
*the-class-standard-object
*)
896 (eq spec
*the-class-structure-object
*)))
897 (let ((sc (class-direct-subclasses spec
)))
899 (mapcan (lambda (class)
900 (mec-all-classes-internal class precompute-p
))
903 (defun mec-all-classes (spec precompute-p
)
904 (let ((classes (mec-all-classes-internal spec precompute-p
)))
905 (if (null (cdr classes
))
907 (let* ((a-classes (cons nil classes
))
909 (loop (when (null (cdr tail
))
910 (return (cdr a-classes
)))
911 (let ((class (cadr tail
))
913 (if (dolist (c ttail nil
)
914 (when (eq class c
) (return t
)))
915 (setf (cdr tail
) (cddr tail
))
916 (setf tail
(cdr tail
)))))))))
918 (defun mec-all-class-lists (spec-list precompute-p
)
921 (let* ((car-all-classes (mec-all-classes (car spec-list
)
923 (all-class-lists (mec-all-class-lists (cdr spec-list
)
925 (mapcan (lambda (list)
926 (mapcar (lambda (c) (cons c list
)) car-all-classes
))
929 (defun make-emf-cache (generic-function valuep cache classes-list new-class
)
930 (let* ((arg-info (gf-arg-info generic-function
))
931 (nkeys (arg-info-nkeys arg-info
))
932 (metatypes (arg-info-metatypes arg-info
))
933 (wrappers (unless (eq nkeys
1) (make-list nkeys
)))
934 (precompute-p (gf-precompute-dfun-and-emf-p arg-info
))
935 (default '(default)))
936 (flet ((add-class-list (classes)
937 (when (or (null new-class
) (memq new-class classes
))
938 (let ((wrappers (get-wrappers-from-classes
939 nkeys wrappers classes metatypes
)))
941 (eq default
(probe-cache cache wrappers default
)))
942 (let ((value (cond ((eq valuep t
)
943 (sdfun-for-caching generic-function
945 ((eq valuep
:constant-value
)
946 (value-for-caching generic-function
948 (setq cache
(fill-cache cache wrappers value
))))))))
950 (mapc #'add-class-list classes-list
)
951 (dolist (method (generic-function-methods generic-function
))
952 (mapc #'add-class-list
953 (mec-all-class-lists (method-specializers method
)
957 (defmacro class-test
(arg class
)
958 (cond ((eq class
*the-class-t
*)
960 ((eq class
*the-class-slot-object
*)
961 `(not (typep (classoid-of ,arg
)
962 'built-in-classoid
)))
963 ((eq class
*the-class-std-object
*)
964 `(or (std-instance-p ,arg
) (fsc-instance-p ,arg
)))
965 ((eq class
*the-class-standard-object
*)
966 `(std-instance-p ,arg
))
967 ((eq class
*the-class-funcallable-standard-object
*)
968 `(fsc-instance-p ,arg
))
970 `(typep ,arg
',(class-name class
)))))
972 (defmacro class-eq-test
(arg class
)
973 `(eq (class-of ,arg
) ',class
))
975 (defmacro eql-test
(arg object
)
976 `(eql ,arg
',object
))
978 (defun dnet-methods-p (form)
980 (or (eq (car form
) 'methods
)
981 (eq (car form
) 'unordered-methods
))))
983 ;;; This is CASE, but without gensyms.
984 (defmacro scase
(arg &rest clauses
)
985 `(let ((.case-arg.
,arg
))
986 (cond ,@(mapcar (lambda (clause)
987 (list* (cond ((null (car clause
))
989 ((consp (car clause
))
990 (if (null (cdar clause
))
995 ((member (car clause
) '(t otherwise
))
998 `(eql .case-arg.
',(car clause
))))
1003 (defmacro mcase
(arg &rest clauses
) `(scase ,arg
,@clauses
))
1005 (defun generate-discrimination-net (generic-function methods types sorted-p
)
1006 (let* ((arg-info (gf-arg-info generic-function
))
1007 (precedence (arg-info-precedence arg-info
)))
1008 (generate-discrimination-net-internal
1009 generic-function methods types
1010 (lambda (methods known-types
)
1013 (let ((sorted-methods nil
))
1015 (copy-list methods
) precedence
1017 (when sorted-methods
(return-from one-order-p nil
))
1018 (setq sorted-methods methods
)))
1019 (setq methods sorted-methods
))
1021 `(methods ,methods
,known-types
)
1022 `(unordered-methods ,methods
,known-types
)))
1023 (lambda (position type true-value false-value
)
1024 (let ((arg (dfun-arg-symbol position
)))
1025 (if (eq (car type
) 'eql
)
1026 (let* ((false-case-p (and (consp false-value
)
1027 (or (eq (car false-value
) 'scase
)
1028 (eq (car false-value
) 'mcase
))
1029 (eq arg
(cadr false-value
))))
1030 (false-clauses (if false-case-p
1032 `((t ,false-value
))))
1033 (case-sym (if (and (dnet-methods-p true-value
)
1035 (eq (car false-value
) 'mcase
)
1036 (dnet-methods-p false-value
)))
1039 (type-sym `(,(cadr type
))))
1041 (,type-sym
,true-value
)
1043 `(if ,(let ((arg (dfun-arg-symbol position
)))
1045 (class `(class-test ,arg
,(cadr type
)))
1046 (class-eq `(class-eq-test ,arg
,(cadr type
)))))
1051 (defun class-from-type (type)
1052 (if (or (atom type
) (eq (car type
) t
))
1055 (and (dolist (type (cdr type
) *the-class-t
*)
1056 (when (and (consp type
) (not (eq (car type
) 'not
)))
1057 (return (class-from-type type
)))))
1059 (eql (class-of (cadr type
)))
1060 (class-eq (cadr type
))
1061 (class (cadr type
)))))
1063 (defun precompute-effective-methods (gf caching-p
&optional classes-list-p
)
1064 (let* ((arg-info (gf-arg-info gf
))
1065 (methods (generic-function-methods gf
))
1066 (precedence (arg-info-precedence arg-info
))
1067 (*in-precompute-effective-methods-p
* t
)
1069 (generate-discrimination-net-internal
1071 (lambda (methods known-types
)
1073 (when classes-list-p
1074 (push (mapcar #'class-from-type known-types
) classes-list
))
1075 (let ((no-eql-specls-p (not (methods-contain-eql-specializer-p
1080 (get-secondary-dispatch-function1
1081 gf methods known-types
1082 nil caching-p no-eql-specls-p
))))))
1083 (lambda (position type true-value false-value
)
1084 (declare (ignore position type true-value false-value
))
1087 (if (and (consp type
) (eq (car type
) 'eql
))
1088 `(class-eq ,(class-of (cadr type
)))
1092 ;;; We know that known-type implies neither new-type nor `(not ,new-type).
1093 (defun augment-type (new-type known-type
)
1094 (if (or (eq known-type t
)
1095 (eq (car new-type
) 'eql
))
1097 (let ((so-far (if (and (consp known-type
) (eq (car known-type
) 'and
))
1099 (list known-type
))))
1100 (unless (eq (car new-type
) 'not
)
1102 (mapcan (lambda (type)
1103 (unless (*subtypep new-type type
)
1108 `(and ,new-type
,@so-far
)))))
1110 (defun generate-discrimination-net-internal
1111 (gf methods types methods-function test-fun type-function
)
1112 (let* ((arg-info (gf-arg-info gf
))
1113 (precedence (arg-info-precedence arg-info
))
1114 (nreq (arg-info-number-required arg-info
))
1115 (metatypes (arg-info-metatypes arg-info
)))
1116 (labels ((do-column (p-tail contenders known-types
)
1118 (let* ((position (car p-tail
))
1119 (known-type (or (nth position types
) t
)))
1120 (if (eq (nth position metatypes
) t
)
1121 (do-column (cdr p-tail
) contenders
1122 (cons (cons position known-type
)
1124 (do-methods p-tail contenders
1125 known-type
() known-types
)))
1126 (funcall methods-function contenders
1127 (let ((k-t (make-list nreq
)))
1128 (dolist (index+type known-types
)
1129 (setf (nth (car index
+type
) k-t
)
1132 (do-methods (p-tail contenders known-type winners known-types
)
1134 ;; is a (sorted) list of methods that must be discriminated.
1136 ;; is the type of this argument, constructed from tests
1139 ;; is a (sorted) list of methods that are potentially
1140 ;; applicable after the discrimination has been made.
1141 (if (null contenders
)
1142 (do-column (cdr p-tail
)
1144 (cons (cons (car p-tail
) known-type
)
1146 (let* ((position (car p-tail
))
1147 (method (car contenders
))
1148 (specl (nth position
(method-specializers method
)))
1149 (type (funcall type-function
1150 (type-from-specializer specl
))))
1151 (multiple-value-bind (app-p maybe-app-p
)
1152 (specializer-applicable-using-type-p type known-type
)
1153 (flet ((determined-to-be (truth-value)
1154 (if truth-value app-p
(not maybe-app-p
)))
1155 (do-if (truth &optional implied
)
1156 (let ((ntype (if truth type
`(not ,type
))))
1161 (augment-type ntype known-type
))
1163 (append winners
`(,method
))
1166 (cond ((determined-to-be nil
) (do-if nil t
))
1167 ((determined-to-be t
) (do-if t t
))
1168 (t (funcall test-fun position type
1169 (do-if t
) (do-if nil
))))))))))
1170 (do-column precedence methods
()))))
1172 (defun compute-secondary-dispatch-function (generic-function net
&optional
1173 method-alist wrappers
)
1174 (function-funcall (compute-secondary-dispatch-function1 generic-function net
)
1175 method-alist wrappers
))
1177 (defvar *eq-case-table-limit
* 15)
1178 (defvar *case-table-limit
* 10)
1180 (defun compute-mcase-parameters (case-list)
1181 (unless (eq t
(caar (last case-list
)))
1182 (error "The key for the last case arg to mcase was not T"))
1183 (let* ((eq-p (dolist (case case-list t
)
1184 (unless (or (eq (car case
) t
)
1185 (symbolp (caar case
)))
1187 (len (1- (length case-list
)))
1188 (type (cond ((= len
1)
1192 *eq-case-table-limit
*
1193 *case-table-limit
*))
1199 (defmacro mlookup
(key info default
&optional eq-p type
)
1200 (unless (or (eq eq-p t
) (null eq-p
))
1201 (bug "Invalid eq-p argument: ~S" eq-p
))
1205 (declare (optimize (inhibit-warnings 3)))
1206 (,(if eq-p
'eq
'eql
) ,key
(car ,info
)))
1210 `(dolist (e ,info
,default
)
1212 (declare (optimize (inhibit-warnings 3)))
1213 (,(if eq-p
'eq
'eql
) (car e
) ,key
))
1216 `(gethash ,key
,info
,default
))))
1218 (defun net-test-converter (form)
1220 (default-test-converter form
)
1222 ((invoke-effective-method-function invoke-fast-method-call
)
1229 `(mlookup ,(cadr form
)
1232 ,@(compute-mcase-parameters (cddr form
))))
1233 (t (default-test-converter form
)))))
1235 (defun net-code-converter (form)
1237 (default-code-converter form
)
1239 ((methods unordered-methods
)
1240 (let ((gensym (gensym)))
1244 (let ((mp (compute-mcase-parameters (cddr form
)))
1245 (gensym (gensym)) (default (gensym)))
1246 (values `(mlookup ,(cadr form
) ,gensym
,default
,@mp
)
1247 (list gensym default
))))
1249 (default-code-converter form
)))))
1251 (defun net-constant-converter (form generic-function
)
1252 (or (let ((c (methods-converter form generic-function
)))
1255 (default-constant-converter form
)
1258 (let* ((mp (compute-mcase-parameters (cddr form
)))
1259 (list (mapcar (lambda (clause)
1260 (let ((key (car clause
))
1261 (meth (cadr clause
)))
1262 (cons (if (consp key
) (car key
) key
)
1264 meth generic-function
))))
1266 (default (car (last list
))))
1267 (list (list* :mcase mp
(nbutlast list
))
1270 (default-constant-converter form
))))))
1272 (defun methods-converter (form generic-function
)
1273 (cond ((and (consp form
) (eq (car form
) 'methods
))
1275 (get-effective-method-function1 generic-function
(cadr form
))))
1276 ((and (consp form
) (eq (car form
) 'unordered-methods
))
1277 (default-secondary-dispatch-function generic-function
))))
1279 (defun convert-methods (constant method-alist wrappers
)
1280 (if (and (consp constant
)
1281 (eq (car constant
) '.methods.
))
1282 (funcall (cdr constant
) method-alist wrappers
)
1285 (defun convert-table (constant method-alist wrappers
)
1286 (cond ((and (consp constant
)
1287 (eq (car constant
) :mcase
))
1288 (let ((alist (mapcar (lambda (k+m
)
1290 (convert-methods (cdr k
+m
)
1294 (mp (cadr constant
)))
1301 (let ((table (make-hash-table :test
(if (car mp
) 'eq
'eql
))))
1303 (setf (gethash (car k
+m
) table
) (cdr k
+m
)))
1306 (defun compute-secondary-dispatch-function1 (generic-function net
1307 &optional function-p
)
1309 ((and (eq (car net
) 'methods
) (not function-p
))
1310 (get-effective-method-function1 generic-function
(cadr net
)))
1312 (let* ((name (generic-function-name generic-function
))
1313 (arg-info (gf-arg-info generic-function
))
1314 (metatypes (arg-info-metatypes arg-info
))
1315 (applyp (arg-info-applyp arg-info
))
1316 (fmc-arg-info (cons (length metatypes
) applyp
))
1317 (arglist (if function-p
1318 (make-dfun-lambda-list metatypes applyp
)
1319 (make-fast-method-call-lambda-list metatypes applyp
))))
1320 (multiple-value-bind (cfunction constants
)
1321 (get-fun1 `(,(if function-p
1325 ,@(unless function-p
1326 `((declare (ignore .pv-cell.
1327 .next-method-call.
))))
1328 (locally (declare #.
*optimize-speed
*)
1330 ,(make-emf-call metatypes applyp
'emf
))))
1331 #'net-test-converter
1332 #'net-code-converter
1334 (net-constant-converter form generic-function
)))
1335 (lambda (method-alist wrappers
)
1336 (let* ((alist (list nil
))
1338 (dolist (constant constants
)
1339 (let* ((a (or (dolist (a alist nil
)
1340 (when (eq (car a
) constant
)
1344 constant method-alist wrappers
)
1346 constant method-alist wrappers
)))))
1348 (setf (cdr alist-tail
) new
)
1349 (setf alist-tail new
)))
1350 (let ((function (apply cfunction
(mapcar #'cdr
(cdr alist
)))))
1353 (make-fast-method-call
1354 :function
(set-fun-name function
`(sdfun-method ,name
))
1355 :arg-info fmc-arg-info
))))))))))
1357 (defvar *show-make-unordered-methods-emf-calls
* nil
)
1359 (defun make-unordered-methods-emf (generic-function methods
)
1360 (when *show-make-unordered-methods-emf-calls
*
1361 (format t
"~&make-unordered-methods-emf ~S~%"
1362 (generic-function-name generic-function
)))
1363 (lambda (&rest args
)
1364 (let* ((types (types-from-args generic-function args
'eql
))
1365 (smethods (sort-applicable-methods generic-function
1368 (emf (get-effective-method-function generic-function smethods
)))
1369 (invoke-emf emf args
))))
1371 ;;; The value returned by compute-discriminating-function is a function
1372 ;;; object. It is called a discriminating function because it is called
1373 ;;; when the generic function is called and its role is to discriminate
1374 ;;; on the arguments to the generic function and then call appropriate
1375 ;;; method functions.
1377 ;;; A discriminating function can only be called when it is installed as
1378 ;;; the funcallable instance function of the generic function for which
1379 ;;; it was computed.
1381 ;;; More precisely, if compute-discriminating-function is called with
1382 ;;; an argument <gf1>, and returns a result <df1>, that result must
1383 ;;; not be passed to apply or funcall directly. Rather, <df1> must be
1384 ;;; stored as the funcallable instance function of the same generic
1385 ;;; function <gf1> (using SET-FUNCALLABLE-INSTANCE-FUNCTION). Then the
1386 ;;; generic function can be passed to funcall or apply.
1388 ;;; An important exception is that methods on this generic function are
1389 ;;; permitted to return a function which itself ends up calling the value
1390 ;;; returned by a more specific method. This kind of `encapsulation' of
1391 ;;; discriminating function is critical to many uses of the MOP.
1393 ;;; As an example, the following canonical case is legal:
1395 ;;; (defmethod compute-discriminating-function ((gf my-generic-function))
1396 ;;; (let ((std (call-next-method)))
1398 ;;; (print (list 'call-to-gf gf arg))
1399 ;;; (funcall std arg))))
1401 ;;; Because many discriminating functions would like to use a dynamic
1402 ;;; strategy in which the precise discriminating function changes with
1403 ;;; time it is important to specify how a discriminating function is
1404 ;;; permitted itself to change the funcallable instance function of the
1405 ;;; generic function.
1407 ;;; Discriminating functions may set the funcallable instance function
1408 ;;; of the generic function, but the new value must be generated by making
1409 ;;; a call to COMPUTE-DISCRIMINATING-FUNCTION. This is to ensure that any
1410 ;;; more specific methods which may have encapsulated the discriminating
1411 ;;; function will get a chance to encapsulate the new, inner discriminating
1414 ;;; This implies that if a discriminating function wants to modify itself
1415 ;;; it should first store some information in the generic function proper,
1416 ;;; and then call compute-discriminating-function. The appropriate method
1417 ;;; on compute-discriminating-function will see the information stored in
1418 ;;; the generic function and generate a discriminating function accordingly.
1420 ;;; The following is an example of a discriminating function which modifies
1421 ;;; itself in accordance with this protocol:
1423 ;;; (defmethod compute-discriminating-function ((gf my-generic-function))
1425 ;;; (cond (<some condition>
1426 ;;; <store some info in the generic function>
1427 ;;; (set-funcallable-instance-function
1429 ;;; (compute-discriminating-function gf))
1430 ;;; (funcall gf arg))
1432 ;;; <call-a-method-of-gf>))))
1434 ;;; Whereas this code would not be legal:
1436 ;;; (defmethod compute-discriminating-function ((gf my-generic-function))
1438 ;;; (cond (<some condition>
1439 ;;; (set-funcallable-instance-function
1441 ;;; (lambda (a) ..))
1442 ;;; (funcall gf arg))
1444 ;;; <call-a-method-of-gf>))))
1446 ;;; NOTE: All the examples above assume that all instances of the class
1447 ;;; my-generic-function accept only one argument.
1449 (defun slot-value-using-class-dfun (class object slotd
)
1450 (declare (ignore class
))
1451 (function-funcall (slot-definition-reader-function slotd
) object
))
1453 (defun setf-slot-value-using-class-dfun (new-value class object slotd
)
1454 (declare (ignore class
))
1455 (function-funcall (slot-definition-writer-function slotd
) new-value object
))
1457 (defun slot-boundp-using-class-dfun (class object slotd
)
1458 (declare (ignore class
))
1459 (function-funcall (slot-definition-boundp-function slotd
) object
))
1461 (defmethod compute-discriminating-function ((gf standard-generic-function
))
1462 (with-slots (dfun-state arg-info
) gf
1463 (typecase dfun-state
1464 (null (let ((name (generic-function-name gf
)))
1465 (when (eq name
'compute-applicable-methods
)
1466 (update-all-c-a-m-gf-info gf
))
1467 (cond ((eq name
'slot-value-using-class
)
1468 (update-slot-value-gf-info gf
'reader
)
1469 #'slot-value-using-class-dfun
)
1470 ((equal name
'(setf slot-value-using-class
))
1471 (update-slot-value-gf-info gf
'writer
)
1472 #'setf-slot-value-using-class-dfun
)
1473 ((eq name
'slot-boundp-using-class
)
1474 (update-slot-value-gf-info gf
'boundp
)
1475 #'slot-boundp-using-class-dfun
)
1476 ((gf-precompute-dfun-and-emf-p arg-info
)
1477 (make-final-dfun gf
))
1479 (make-initial-dfun gf
)))))
1480 (function dfun-state
)
1481 (cons (car dfun-state
)))))
1483 (defmethod update-gf-dfun ((class std-class
) gf
)
1484 (let ((*new-class
* class
)
1485 #||
(name (generic-function-name gf
)) ||
#
1486 (arg-info (gf-arg-info gf
)))
1488 ((eq name
'slot-value-using-class
)
1489 (update-slot-value-gf-info gf
'reader
))
1490 ((equal name
'(setf slot-value-using-class
))
1491 (update-slot-value-gf-info gf
'writer
))
1492 ((eq name
'slot-boundp-using-class
)
1493 (update-slot-value-gf-info gf
'boundp
))
1495 ((gf-precompute-dfun-and-emf-p arg-info
)
1496 (multiple-value-bind (dfun cache info
)
1497 (make-final-dfun-internal gf
)
1498 (set-dfun gf dfun cache info
) ; lest the cache be freed twice
1499 (update-dfun gf dfun cache info
))))))
1501 (defmethod function-keywords ((method standard-method
))
1502 (multiple-value-bind (nreq nopt keysp restp allow-other-keys-p keywords
)
1503 (analyze-lambda-list (if (consp method
)
1504 (early-method-lambda-list method
)
1505 (method-lambda-list method
)))
1506 (declare (ignore nreq nopt keysp restp
))
1507 (values keywords allow-other-keys-p
)))
1509 (defun method-ll->generic-function-ll
(ll)
1510 (multiple-value-bind
1511 (nreq nopt keysp restp allow-other-keys-p keywords keyword-parameters
)
1512 (analyze-lambda-list ll
)
1513 (declare (ignore nreq nopt keysp restp allow-other-keys-p keywords
))
1514 (remove-if (lambda (s)
1515 (or (memq s keyword-parameters
)
1516 (eq s
'&allow-other-keys
)))
1519 ;;; This is based on the rules of method lambda list congruency defined in
1520 ;;; the spec. The lambda list it constructs is the pretty union of the
1521 ;;; lambda lists of all the methods. It doesn't take method applicability
1522 ;;; into account at all yet.
1523 (defmethod generic-function-pretty-arglist
1524 ((generic-function standard-generic-function
))
1525 (let ((methods (generic-function-methods generic-function
)))
1528 ;; arglist is constructed from the GF's methods - maybe with
1529 ;; keys and rest stuff added
1530 (multiple-value-bind (required optional rest key allow-other-keys
)
1531 (method-pretty-arglist (car methods
))
1532 (dolist (m (cdr methods
))
1533 (multiple-value-bind (method-key-keywords
1534 method-allow-other-keys
1536 (function-keywords m
)
1537 ;; we've modified function-keywords to return what we want as
1538 ;; the third value, no other change here.
1539 (declare (ignore method-key-keywords
))
1540 (setq key
(union key method-key
))
1541 (setq allow-other-keys
(or allow-other-keys
1542 method-allow-other-keys
))))
1543 (when allow-other-keys
1544 (setq arglist
'(&allow-other-keys
)))
1546 (setq arglist
(nconc (list '&key
) key arglist
)))
1548 (setq arglist
(nconc (list '&rest rest
) arglist
)))
1550 (setq arglist
(nconc (list '&optional
) optional arglist
)))
1551 (nconc required arglist
)))
1552 ;; otherwise we take the lambda-list from the GF directly, with no
1553 ;; other 'keys' added ...
1554 (let ((lambda-list (generic-function-lambda-list generic-function
)))
1557 (defmethod method-pretty-arglist ((method standard-method
))
1562 (allow-other-keys nil
)
1564 (arglist (method-lambda-list method
)))
1565 (dolist (arg arglist
)
1566 (cond ((eq arg
'&optional
) (setq state
'optional
))
1567 ((eq arg
'&rest
) (setq state
'rest
))
1568 ((eq arg
'&key
) (setq state
'key
))
1569 ((eq arg
'&allow-other-keys
) (setq allow-other-keys t
))
1570 ((memq arg lambda-list-keywords
))
1573 (required (push arg required
))
1574 (optional (push arg optional
))
1575 (key (push arg key
))
1576 (rest (setq rest arg
))))))
1577 (values (nreverse required
)