From: Andreas F. <as...@vo...> - 2003-08-26 11:29:26
|
Hi, I'm playing with method combinations, and have discovered that when I redefine the generic function to pass a different parameter to the method combination (in this case it's order, :most-specific-last vs :most-specific-first), I have to reload the GF definition as well as at least one method definition to make the change take place. It happens with this combination of MC, GF and methods: ;; --------------------- cut ------------------ (define-method-combination setup-teardown (&optional (order :most-specific-last) &aux (anti-order (if (eql order :most-specific-last) :most-specific-first :most-specific-last))) ((setup (:setup) :order order) (before (:before)) (primary () :required t :order order) (after (:after)) (teardown (:teardown) :order anti-order)) (flet ((call-methods (methods) (mapcar #'(lambda (method) `(call-method ,method)) methods))) (let* ((inner-form (if (or before after (rest primary)) `(multiple-value-prog1 (progn ,@(call-methods before) (call-method ,(first primary) ,(rest primary))) ,@(call-methods (reverse after))) `(call-method ,(first primary)))) (form (if (or setup teardown) `(unwind-protect (progn ,@(call-methods setup) ,inner-form) ,@(call-methods teardown)) inner-form))) form))) (defclass a () ()) (defclass b (a) ()) (defgeneric foo (obj) (:method-combination setup-teardown :most-specific-first)) (defmethod foo :setup ((o a)) (format t "A: setting up ~A~%" o)) (defmethod foo :setup ((o b)) (format t "B: setting up ~A~%" o)) (defmethod foo :teardown ((o a)) (format t "A: tearing down ~A~%" o)) (defmethod foo :teardown ((o b)) (format t "B: tearing down ~A~%" o)) (defmethod foo (o) (declare (ignore o)) (format t "hahaha~%")) ;; --------------------- cut ------------------ To test: * (foo (make-instance 'b)) B: setting up #<B {48580819}> A: setting up #<B {48580819}> hahaha A: tearing down #<B {48580819}> B: tearing down #<B {48580819}> NIL * ;; reloading the GF definition (defgeneric foo (obj) (:method-combination setup-teardown :most-specific-last)) * ;; should give A, B; hahaha; B, A now: (foo (make-instance 'b)) B: setting up #<B {48BE20D1}> A: setting up #<B {48BE20D1}> hahaha A: tearing down #<B {48BE20D1}> B: tearing down #<B {48BE20D1}> NIL * ;; BUT: (progn (defgeneric foo (obj) (:method-combination setup-teardown :most-specific-last)) (defmethod foo :setup ((o a)) (format t "A: setting up ~A~%" o))) * (foo (make-instance 'b)) A: setting up #<B {48CFD5A9}> B: setting up #<B {48CFD5A9}> hahaha B: tearing down #<B {48CFD5A9}> A: tearing down #<B {48CFD5A9}> NIL * Is this expected behaviour? Thanks, -- Andreas Fuchs, <as...@ac...>, as...@ja..., antifuchs |
From: Gerd M. <ger...@t-...> - 2003-08-26 18:40:00
|
Andreas Fuchs <as...@vo...> writes: > (define-method-combination setup-teardown [...] > Is this expected behaviour? I'd expect this to happen because I've incidentally just today read a comment and code in PCL again which explicitly makes the assumption that the method combination of a gf doesn't change. Someone (tm) would have to check if that's compliant with whatever is relevant. And, I'd almost bet a small amount that adding the DOLIST to the following method would make your case work (CMUCL + untested). (in-package :pcl) (defmethod reinitialize-instance :after ((gf standard-generic-function) &rest args &key (lambda-list nil lambda-list-p) (argument-precedence-order nil argument-precedence-order-p)) (dolist (method (generic-function-methods gf)) (remhash method *effective-method-table*)) (with-slots (arg-info) gf (if lambda-list-p (if argument-precedence-order-p (set-arg-info gf :lambda-list lambda-list :argument-precedence-order argument-precedence-order) (set-arg-info gf :lambda-list lambda-list)) (set-arg-info gf)) (when (and (arg-info-valid-p arg-info) args (or lambda-list-p (cddr args))) (update-dfun gf)))) |
From: Andreas F. <as...@vo...> - 2003-08-26 20:57:50
|
Today, Gerd Moellmann <ger...@t-...> wrote: > I'd expect this to happen because I've incidentally just today read a > comment and code in PCL again which explicitly makes the assumption > that the method combination of a gf doesn't change. Someone (tm) > would have to check if that's compliant with whatever is relevant. Hmwell. quoting from <URL:http://www.lisp.org/HyperSpec/Body/fun_ensure-ge_ric-function.html#ensure-generic-function>: "If function-name specifies a generic function that has a different value for any of the following arguments, the generic function is modified to have the new value: :argument-precedence-order, :declare, :documentation, :method-combination" This does not say anything about recomputing the effective method, though. And this is how PCL currently behaves. I could not find mention of the effects of GF redefinition and what happens when a method combination actually changes. Maybe somebody with more Spec Reading Ability can help? > And, I'd almost bet a small amount that adding the DOLIST to the > following method would make your case work (CMUCL + untested). And you'd almost have won an equally small amount (-: > (in-package :pcl) with (in-package :sb-pcl), it seems to work like a charm. IMHO the current behaviour re. method combination changes is not optimal (or obvious). If you decide to keep it, may I suggest raising a STYLE-WARNING? Thanks, -- Andreas Fuchs, <as...@ac...>, as...@ja..., antifuchs |
From: Gerd M. <ger...@t-...> - 2003-08-27 09:00:48
|
Andreas Fuchs <as...@vo...> writes: > IMHO the current behaviour re. method combination changes is not optimal > (or obvious). If you decide to keep it, may I suggest raising a > STYLE-WARNING? I think I'll install a change that uncaches emfs. AFAICS, it costs almost nothing, and as you say, the current behavior is not very obvious. Thanks for trying out the patch. |