From: Jim Newton
Subject: initializint a CLOS class instance
Date: 
Message-ID: <2s5u83F1erl9fU1@uni-berlin.de>
I'd like to define some additional actions to happen to
an instance of my class after it is initialized with all the
:initform and :initarg specs etc...

I see two ways of doing this.

1) I could define an after method
2) I could define a primary method and call call-next-method.

Are these two equivalent?  Or is there some reason I'd want
to do one instead of the other?

-jim

From: Joel Ray Holveck
Subject: Re: initializint a CLOS class instance
Date: 
Message-ID: <87sm8yylmq.fsf@thor.piquan.org>
> 1) I could define an after method
> 2) I could define a primary method and call call-next-method.
> Are these two equivalent?  Or is there some reason I'd want
> to do one instead of the other?

Not quite.  If you've subclassed a child class, and there's an :after
method specialized on the child class, then a primary method
specialized on your class will happen before their :after method,
while an :after method specialized on your class will execute after
their :after method.  Confused?  I am, so let's dig into the example
bin.

Here's something to demonstrate this.  It doesn't go into multiple
inheritance or multiple dispatch, which can get... interesting.

    (defclass foo () ())
    (defclass bar (foo) ())
    (defgeneric frob (obj))
    (defmethod frob ((obj foo))
      (print "Frobbing foo"))
    (defmethod frob ((obj bar))
      (print "Starting to frob bar")
      (call-next-method)
      (print "Finished frobbing bar"))
    (defmethod frob :before ((obj foo))
      (print "Pre-frobbing foo"))
    (defmethod frob :before ((obj bar))
      (print "Pre-frobbing bar"))
    (defmethod frob :after ((obj foo))
      (print "Post-frobbing foo"))
    (defmethod frob :after ((obj bar))
      (print "Post-frobbing bar"))
    (defmethod frob :around ((obj foo))
      (print "Starting to around-frob foo")
      (call-next-method)
      (print "Done around-frobbing foo"))
    (defmethod frob :around ((obj bar))
      (print "Starting to around-frob bar")
      (call-next-method)
      (print "Done around-frobbing bar"))
    (frob (make-instance 'bar))

;; produces:

    "Starting to around-frob bar" 
    "Starting to around-frob foo" 
    "Pre-frobbing bar" 
    "Pre-frobbing foo" 
    "Starting to frob bar" 
    "Frobbing foo" 
    "Finished frobbing bar" 
    "Post-frobbing foo" 
    "Post-frobbing bar" 
    "Done around-frobbing foo" 
    "Done around-frobbing bar" 

So, here's what we see.  Note that the nested elements only take place
if call-next-method is called, of course.

(around BAR
  (around FOO
    (before BAR)
    (before FOO)
    (primary BAR
      (primary FOO))
    (after FOO)
    (after BAR)))

So, here, suppose BAR is your class, inherited from FOO.  If you
define an :after method, but FOO has an :after method, then FOO's
:after will execute first.  But if you define something at the end of
a primary method, then your code will execute first.  If there's a
reason that FOO's :after method may depend on your code having
completed, then you'd need to do it in a primary method.  OTOH, if
not, then you may be better off using an :after method, for the
following reasons.

You may also want to think about your class as FOO, and somebody
subclasses BAR from it.  Now, if you define yours as part of the
primary method, then they'll have no chance to execute any code
inbetween when (initialize-instance standard-object) runs and when
your code runs.  But if you define yours as an :after method, then the
guy who writes BAR can inject something by defining a primary method,
if he really needs to.

By the way, I'm really using your post as an opportunity to think
about these things myself.  I've been doing a fair bit of method
combination work in my current project, and haven't thought through my
combinations as well as I should have done.  So this post is a good
exercise for me.

After writing all of this, I'd probably say, tend towards :after
unless there was a good reason to use a primary method.

To get the implicit opinion of some folks who are more experienced
than I am, I just looked at what Lispworks does, by looking at
(generic-function-methods #'initialize-instance).  As I have it loaded
now (CAPI, KW, CLIM, SQL, and Swank), it defines 157 :after methods on
#'initialize-instance, 7 :around methods, and only one primary
method-- and that's on standard-object itself.  CMUCL (with Gray
Streams, ASDF, Swank, and nregex) defines only one primary method
(pcl::slot-object, which is a superclass of standard-object), and one
:after method (on standard-generic-function).

Hope this helps you; it's almost certainly helped me.

Cheers,
joelh

-- 
Joel Ray Holveck - ·····@piquan.org
   Fourth law of programming:
   Anything that can go wrong wi
sendmail: segmentation violation - core dumped
From: Larry Clapp
Subject: Re: initializint a CLOS class instance
Date: 
Message-ID: <slrncm07bp.2uo.larry@theclapp.ddts.net>
In article <··············@thor.piquan.org>, Joel Ray Holveck wrote:
>> 1) I could define an after method
>> 2) I could define a primary method and call call-next-method.
>> Are these two equivalent?  Or is there some reason I'd want
>> to do one instead of the other?
> 
> Not quite.  If you've subclassed a child class, and there's an
> :after method specialized on the child class, then a primary method
> specialized on your class will happen before their :after method,
> while an :after method specialized on your class will execute after
> their :after method.  Confused?  I am, so let's dig into the example
> bin.
> 
> Here's something to demonstrate this.
[snip a nice illustration of before/after/around method-invocation
order.]

Also remember, you can "jump out of the system"[1] (that is,
suspend/augment the normal flow of before/after/around) by calling
some other generic function in your base-class method.

Expanding on Joel's example:

(defclass foo () ())
(defclass bar (foo) ())
(defclass baz (bar) ())		; new class
(defclass quux (bar) ())	; new class
(defclass quuux (bar) ())	; new class

;	foo
;	 |
;	bar
;	 |
;   +----+------+
;  baz  quux  quuux

(defgeneric frob (obj))
(defmethod frob ((obj foo))
  (print "Frobbing foo")
  (do-x obj)				; new code
  (print "Done frobbing foo"))		; new code
(defmethod frob ((obj bar))
  (print "Starting to frob bar")
  (call-next-method)
  (print "Finished frobbing bar"))
(defmethod frob :before ((obj foo))
  (print "Pre-frobbing foo"))
(defmethod frob :before ((obj bar))
  (print "Pre-frobbing bar"))
(defmethod frob :after ((obj foo))
  (print "Post-frobbing foo"))
(defmethod frob :after ((obj bar))
  (print "Post-frobbing bar"))
(defmethod frob :around ((obj foo))
  (print "Starting to around-frob foo")
  (call-next-method)
  (print "Done around-frobbing foo"))
(defmethod frob :around ((obj bar))
  (print "Starting to around-frob bar")
  (call-next-method)
  (print "Done around-frobbing bar"))

;; new code
(defmethod do-x ((obj foo)) (print "do-x foo"))
(defmethod do-x ((obj bar)) (print "do-x bar"))
(defmethod do-x ((obj baz)) (print "do-x baz"))
(defmethod do-x ((obj quux)) (print "do-x quux"))
(defmethod do-x ((obj quuux)) (print "do-x quuux"))

CL-USER> (frob (make-instance 'foo))

"Starting to around-frob foo" 
"Pre-frobbing foo" 
"Frobbing foo" 
"do-x foo" 				; do-x on foo
"Done frobbing foo" 
"Post-frobbing foo" 
"Done around-frobbing foo" 

CL-USER> (frob (make-instance 'bar))

"Starting to around-frob bar" 
"Starting to around-frob foo" 
"Pre-frobbing bar" 
"Pre-frobbing foo" 
"Starting to frob bar" 
"Frobbing foo" 
"do-x bar" 				; do-x on bar
"Done frobbing foo" 
"Finished frobbing bar" 
"Post-frobbing foo" 
"Post-frobbing bar" 
"Done around-frobbing foo" 
"Done around-frobbing bar" 

CL-USER> (frob (make-instance 'baz))

; ...
"Frobbing foo" 
"do-x baz" 				; do-x on baz
"Done frobbing foo" 
; ...

CL-USER> (frob (make-instance 'quux))

; ...
"Frobbing foo" 
"do-x quux" 				; do-x on quux
"Done frobbing foo" 
; ...

CL-USER> (frob (make-instance 'quuux))

; ...
"Frobbing foo" 
"do-x quuux" 				; do-x on quuux
"Done frobbing foo" 
; ...

> So, here's what we see.  Note that the nested elements only take
> place if call-next-method is called, of course.
> 
> (around BAR
>   (around FOO
>     (before BAR)
>     (before FOO)
>     (primary BAR
        (primary FOO
	  (do-x FOO/BAR/BAZ/QUUX/QUUUX, as appropriate)))
>     (after FOO)
>     (after BAR)))

This can come in especially handy when you remember that you can
define before/after/around methods on do-x just like any other method.

See also Tim Bradshaw's http://www.tfeb.org/lisp/hax.html#WRAPPING-STANDARD
for a portable method of defining wrapping methods, or "hooks":

  Wrapping methods are like around methods but happen outside them
  (so: before and after), and the least specific wrapping method is
  outermost. Thus, if you write a completely unspecific wrapping
  method, it will always wrap around any other methods.

(Note: I haven't tried Tim's code; it sounds and looks pretty handy,
but I've no idea if it actually works.  Caveat User.)

[1] See _Godel, Escher, Bach_, by Douglas Hofstadter

-- 
Larry Clapp / ·····@theclapp.org

-- 
Larry Clapp / ·····@theclapp.org
Use Lisp from Vim: VILisp: http://vim.sourceforge.net/script.php?script_id=221
From: Pascal Costanza
Subject: Re: initializint a CLOS class instance
Date: 
Message-ID: <cjkujh$meu$1@newsreader2.netcologne.de>
Jim Newton wrote:
> I'd like to define some additional actions to happen to
> an instance of my class after it is initialized with all the
> :initform and :initarg specs etc...
> 
> I see two ways of doing this.
> 
> 1) I could define an after method
> 2) I could define a primary method and call call-next-method.
> 
> Are these two equivalent?  Or is there some reason I'd want
> to do one instead of the other?

Presumably you mean methods for initialize-instance. Some CLOS 
implementations (at least Allegro) seem to be able to optimize instance 
generation and initialization if you only define after methods on 
initialize-instance.


Pascal

-- 
Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."
From: Steven M. Haflich
Subject: Re: initializint a CLOS class instance
Date: 
Message-ID: <415E2615.4060702@alum.mit.edu>
Pascal Costanza wrote:

>> 1) I could define an after method
>> 2) I could define a primary method and call call-next-method.
>>
>> Are these two equivalent?  Or is there some reason I'd want
>> to do one instead of the other?
> 
> Presumably you mean methods for initialize-instance.  ...

Jim: Think carefully whether you want to place these methods
(whether :after or :primary or :around) on initialize-instance
or shared-initialize.  The former is called onlty when an
instance is first created, while the latter is called for each
of initialize-instance, reinitialize-instance,
update-instance-for-redefined-class, and
update-instance-for-different-class.

It makes a difference if your application happens to invoke
any of these other protocols, but there is no right answer
to your question about :after vs :primary.  It depends on
the semantics of your objects.

Before you shrug off this issue because your application
doesn't do any class redefinition or class changing, remember
that during development you might find yuorself redefining
classes and not wantnig to restart your lisp session.  So it's
worth thinking about this a little so you aren't surprised
the first time you redefine a class.

One great thing about Lisp is that you can incrementally debug
a complex application with lots of internal state without having
to recompile and restart a fresh image every few minutes.  This
saves a lot of time during development.
From: Peter Herth
Subject: Re: initializint a CLOS class instance
Date: 
Message-ID: <cjltu2$bd9$1@newsreader2.netcologne.de>
Hi!

besides the things said by other posters, from my experiments during writing
Ltk I can point out one difference which gets important in the case of
multiple inheritance. In general, the order of method invokation is done
by the position of the classes in the inheritance tree. But what we actuall
have is three sections:

1) around
2) before/after methods
3) primary methods

So the call order is (assuming call-next-next method is used where needed):
first around, then before, primary methods, after method and finally the
rest of any pending around method. The catch in my eyes is, that only within
the three sections the class precedence list takes control over the order.
So that gives you a corse control about the call order of your methods by 
selecting on of the three sections. So if you use before/after methods by
"default", you can move selected methods ahead/after in order if you make
them around/primary methods. 
As an example: in Ltk I defined a mixin class called tktextvariable - used
for all widgets which can be associated with a text variable in tk - for
example the entry widget. The problem was, the method creating the
association of the variable with the widget must be run after the widget
has been created. But just using after methods this was impossible, as
the widget creation is done in the after method of initialze-instance
of the entry widget class. The solution for this case was to define
an around method for the tktextvariable class which first does the
call to call-next-method to ensure the widget creation and only then
performs the association with the variable.

Peter

-- 
pet project: http://dawn.netcologne.de
homepage:    http://www.peter-herth.de
lisp stuff:  http://www.peter-herth.de/lisp.html
get Ltk here: http://www.peter-herth.de/ltk/
From: Tim Bradshaw
Subject: Re: initializint a CLOS class instance
Date: 
Message-ID: <1096886484.092834.42670@k26g2000oda.googlegroups.com>
Peter Herth wrote:
> So the call order is (assuming call-next-next method is used where
needed):
> first around, then before, primary methods, after method and finally
the
> rest of any pending around method. The catch in my eyes is, that only
within
> the three sections the class precedence list takes control over the
order.
> So that gives you a corse control about the call order of your
methods by
> selecting on of the three sections. So if you use before/after
methods by
> "default", you can move selected methods ahead/after in order if you
make
> them around/primary methods.

You are also free to define your own method combinations which can do
things in variant orders.  For instance I have a method combination
called `wrapping standard' which is exactly like standard, but has an
additional set of `wrapping' methods, which are like around methods,
but run outside them (before and after) and in the reverse order, so
least-specific-outermost.  This can be nice because it lets the
least-specific class get some overriding control.  The particular case
for which I wanted it was defaulting optional arguments for generic
functions, which is often naturally done by a wrapping method on the
least-specific class.

User-defined method combinations like this seem to be perfectly
efficient on all the implementations I tried.

--tim