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

Re: Yeah! I can convert!



>After months of begging/pleading/demanding/etc. I have finally put my
>foot down and told my project manager:  "I am converting all 29,000+
>of 1.3.2 to 2.0, and you can't stop me!!"  And, while he is a little
>nervous, he knows there is no turning back.
>
>So, hooray for me, but now I find myself learning CLOS as I convert all
>this wonderful MCL1.3.2 ObjectLisp code.  I am studying the example source
>code, and the (simple) question I have is related to the design of methods 
>for initializing instances of objects.  Consider, for example, the code 
>found on page 503 in the manual.  (This is the shapes-code.lisp example).
>
>Looking at the initialize-instance method for the class 'shape-window,
>I notice that the first thing this method does is:
>
>     (apply #'call-next-method window initargs)
>
>My question is:  if the first thing you are going to do is call the
>primary methods defined on the 'window class, why not code the
>#'initialize-instance method on the 'shape-window class as an :after
>method, and then simply remove the call to apply?  I believe this
>would be both more efficient and conceptually correct, or am I 
>missing something really important and/or really basic?
>
>Thanks for your replies.  I realize that both implementations are
>correct, in the sense that both "get the job done", but I am more
>interested in learning good CLOS style and writing long-term maintainable
>source code.  Thanks!
>
>-----------------------------------+--------------------------------------
>Luke Hohmann                       | hohmann@csmil.umich.edu
>University of Michigan             | 313-763-1043 (Office)
>Artificial Intelligence Laboratory | 313-677-0952 (Home)
>1101 Beal Ave                      | 
>Ann Arbor, MI 48109-2110           | "You should do more aerobics!"

Here is a case where 'an AFTER method' and 'a primary method that first
calls CALL-NEXT-METHOD' are not equivalent. It use multiple inheritance.
I am not sure if this behaviour can occur when only single inheritance is
used (maybe a CLOS wiz can answer this one).

Here is the heritance graph for both examples
Both example are the same except that FOO1 will use a primary method
and FOO2 will use an AFTER method.

FOO1 \                   FOO2 \
       BAR                      BAZ
GOO  /                   GOO  /

(defclass foo1 ()
    ())

(defmethod initialize-instance ((self foo1) &key)
  (call-next-method)
  (print "Initializing FOO1"))

(defclass foo2 ()
    ())

(defmethod initialize-instance :after ((self foo2) &key)
  (print "Initializing FOO2"))

(defclass goo ()
    ())

(defmethod initialize-instance ((self goo) &key)
  (call-next-method)
  (print "Initializing GOO"))

(defclass bar (foo1 goo)
    ())

(defmethod initialize-instance ((self bar) &key)
  (call-next-method)
  (print "Initializing BAR"))

(defclass baz (foo2 goo)
    ())

(defmethod initialize-instance ((self baz) &key)
  (call-next-method)
  (print "Initializing BAZ"))

? (make-instance 'bar)

"Initializing GOO" 
"Initializing FOO1" 
"Initializing BAR" 
#<BAR #xBBDCB1>

? (make-instance 'baz)

"Initializing GOO" 
"Initializing BAZ" 
"Initializing FOO2" 
#<BAZ #xBBDEE1>
? 

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.

Hope this helps...

Guillaume Cartier
LACIM, Universite du Quebec a Montreal.
Bureau: (514) 987-4290
E-Mail: cartier@math.uqam.ca