From: Raymond Toy
Subject: around methods and shadowed methods
Date: 
Message-ID: <4nyaj4byrn.fsf@rtp.ericsson.se>
I have a set of classes, say

(defclass basic ()
   ())

(defclass more (basic)
   (;; New slots added
    ))

And a set of methods,

(defmethod process ((b basic) inputs)
   ;; Do something useful
)

For the class MORE, the PROCESS method above is almost right, but I
need to do some more processing on the result.

I can do this by either using an around method:

(defmethod process :around ((m more) inputs)
   (let ((result (call-next-method)))
      (more-processing result)))

Or just call the shadowed method directly:

(defmethod process ((m more) inputs)
   (more-processing (call-next-method)))

Stylistically, is one better than the other?  I'm not expecting any
:before or :after methods for PROCESS on the BASIC class, so both
should do exactly the same processing.

Or is there some other way, like moving the "Do something useful" into
a separate (non-generic) function callable from both methods?

Thanks for any suggestions,

Ray

   

From: Barry Margolin
Subject: Re: around methods and shadowed methods
Date: 
Message-ID: <0bFX2.337$jw4.27311@burlma1-snr2>
In article <··············@rtp.ericsson.se>,
Raymond Toy  <···@rtp.ericsson.se> wrote:
>I can do this by either using an around method:
>
>(defmethod process :around ((m more) inputs)
>   (let ((result (call-next-method)))
>      (more-processing result)))
>
>Or just call the shadowed method directly:
>
>(defmethod process ((m more) inputs)
>   (more-processing (call-next-method)))
>
>Stylistically, is one better than the other?  I'm not expecting any
>:before or :after methods for PROCESS on the BASIC class, so both
>should do exactly the same processing.

What if someone defines a subclass of MORE and defines :BEFORE, :AFTER, or
:AROUND methods.  In that case, the order of invocation of the methods will
be different.

Stylistically, you should use a primary method if the intent is that this
is the primary behavior of the generic function for that class.  You should
use an :AROUND method if you intend this to be behavior that the class adds
to other classes that it's combined with, and if it needs to run around any
auxiliary methods supplied by less specific classes.

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Kent M Pitman
Subject: Re: around methods and shadowed methods
Date: 
Message-ID: <sfw90b4ae4g.fsf@world.std.com>
Raymond Toy <···@rtp.ericsson.se> writes:

> (defmethod process :around ((m more) inputs)
>    (let ((result (call-next-method)))
>       (more-processing result)))
> 
> Or just call the shadowed method directly:
> 
> (defmethod process ((m more) inputs)
>    (more-processing (call-next-method)))
> 

In addition to the issues Barry cited:

  The former method cannot be shadowed.
  The latter method can.

  The former is declarative, permitting easier visual inspection
  and program manipulation.
  The latter is imparative, and as such (in more complex cases)
  can be quite mysterious to programs and even sometimes to people.

When I learned to drive a car [no, not the lisp kind], one of the
great puzzles to me was in a multi-lane road, how did one decide what
lane to drive in.  They all seemed so equivalent (absent some sort of
autobahn rule where one line goes infinitely faster than another).
Yet people were so picky about what lane to be in.  It took me a while
to realize that it wasn't about where you were driving but rather
what you wanted to do next.  The choice was not about the present
but about lookahead.  The same with the choice of methods above.
It's not so much that one is better than the other statically--since
they do the same in some observable circumstances--but more about 
how your program will grow, change, and combine ... the "lane changes"
and "entry/exit ramps" of code development.  I suppose with all the
GII metaphors running around the world, this analogy is a tired one,
but I hope it helps.
From: Raymond Toy
Subject: Re: around methods and shadowed methods
Date: 
Message-ID: <4npv4fbtyu.fsf@rtp.ericsson.se>
>>>>> "Kent" == Kent M Pitman <······@world.std.com> writes:

    Kent> Raymond Toy <···@rtp.ericsson.se> writes:
    >> (defmethod process :around ((m more) inputs)
    >> (let ((result (call-next-method)))
    >> (more-processing result)))
    >> 
    >> Or just call the shadowed method directly:
    >> 
    >> (defmethod process ((m more) inputs)
    >> (more-processing (call-next-method)))
    >> 

    Kent> In addition to the issues Barry cited:

    Kent>   The former method cannot be shadowed.
    Kent>   The latter method can.

    Kent>   The former is declarative, permitting easier visual inspection
    Kent>   and program manipulation.
    Kent>   The latter is imparative, and as such (in more complex cases)
    Kent>   can be quite mysterious to programs and even sometimes to people.

Thanks to you and Barry for the pointers.  I guess the right way to do 
this is to move the common functionality out to a function like so:

(defun do-it (inputs)
   ;; do something useful
)

(defmethod process ((b basis) inputs)
   (do-it inputs))

(defmethod process ((m more) inputs)
   (process-more (do-it inputs)))


This makes sense, preserves the declarative nature of the program, and
allows derived classes and methods to do the expected CLOS things
without manually looking into every class to make sure nothing funny
happens.

Thanks!

Ray