[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Primary vs. :after methods (was: Yeah! I can convert!)



>Date: Thu, 27 Feb 92 12:07:49 -0500
>To: info-mcl@cambridge.apple.com (Macintosh Common Lisp)
>From: cartier@math.uqam.ca (Guillaume Cartier)
>Subject: Re: Yeah! I can convert!

[...]

>I am not sure what all this means and what is the "correct" way of doing
>things. It just shows that the two ways are not equivalent.
>
>It would be GREAT if someone else could shed some light on the pros and cons
>of both approachs.

The place where I have noticed the difference here is that if a method
is specialized on a subclass of a class for which there is an :AFTER
method and the first method does CALL-NEXT-METHOD with changed
arguments, the :AFTER method will not see the changed args. This is
often important in the case of INITIALIZE-INSTANCE, where initargs
are sometimes inserted:

(defclass my-window (window) ())

(defmethod initialize-instance ((self my-window) &rest rest &key
                                (window-show t))
  (declare (dynamic-extent rest))
  (apply #'call-next-method 
         self
         :window-show nil
         rest)
  ; More code here...
  (when window-show
    (window-show self)))

If there is an :AFTER method for INITIALIZE-INSTANCE specialized on
the WINDOW class, and it defaults the value of WINDOW-SHOW, it
will likely not behave as the writer of the method for MY-WINDOW
intended.

Here's a runnable example:

? (defclass foo () ())

? (defclass bar (foo) ())

? (defmethod primary (x y)
    (format t "~&((primary t) ~s ~s)~%" x y))

? (defmethod primary ((x foo) y)
    (call-next-method)
    (format t "~&((primary foo) ~s ~s)~%" x y))

? (defmethod primary ((x bar) y)
    (call-next-method x (1+ y))
    (format t "~&((primary bar) ~s ~s)~%" x y))

? (primary (make-instance 'bar) 1)
((primary t) #<BAR #xEA73F9> 2)
((primary foo) #<BAR #xEA73F9> 2)
((primary bar) #<BAR #xEA73F9> 1)

; Note that the primary method on FOO got the changed value for Y

? (defmethod after (x y)
    (format t "~&((after t) ~s ~s)~%" x y))

? (defmethod after :after ((x foo) y)
    (format t "~&((after foo) ~s ~s)~%" x y))

? (defmethod after ((x bar) y)
    (call-next-method x (1+ y))
    (format t "~&((after bar) ~s ~s)~%" x y))

? (after (make-instance 'bar) 1)
((after t) #<BAR #xEA8049> 2)
((after bar) #<BAR #xEA8049> 1)
((after foo) #<BAR #xEA8049> 1)

Note that the :AFTER method on FOO got the original arguments to
the generic function.