From: Slava Akhmechet
Subject: Method combination problem
Date: 
Message-ID: <87d517usgy.fsf@gmail.com>
I have a problem with CLOS method combination. Perhaps it's because of
a misunderstanding. I have the following setup:

(defgeneric foo (a))

(defmethod foo (a)
  1)

(defmethod foo ((a standard-object))
  2)

(defmethod foo :around (a)
  3)

(defmethod foo :around ((a standard-object))
  (call-next-method a))

It appears that if I make the following call:

(foo some-standard-object)

The expression evaluated to 3, which means that the next most specific
method for 'foo' is the third one, not the second one as I would
expect (I expected the expression to return 2). I run into this in
SBCL and OpenMCL which suggests that the problem here is my
misunderstanding of the issue.

Could someone explain why the third method is considered to be more
specific in this case?
  
-- 
Regards,
Slava Akhmechet.

From: Rainer Joswig
Subject: Re: Method combination problem
Date: 
Message-ID: <joswig-1D66EC.20540911052007@news-europe.giganews.com>
In article <··············@gmail.com>,
 Slava Akhmechet <·········@gmail.com> wrote:

> I have a problem with CLOS method combination. Perhaps it's because of
> a misunderstanding. I have the following setup:
> 
> (defgeneric foo (a))
> 
> (defmethod foo (a)
>   1)
> 
> (defmethod foo ((a standard-object))
>   2)
> 
> (defmethod foo :around (a)
>   3)
> 
> (defmethod foo :around ((a standard-object))
>   (call-next-method a))
> 
> It appears that if I make the following call:
> 
> (foo some-standard-object)
> 
> The expression evaluated to 3, which means that the next most specific
> method for 'foo' is the third one, not the second one as I would
> expect (I expected the expression to return 2). I run into this in
> SBCL and OpenMCL which suggests that the problem here is my
> misunderstanding of the issue.
> 
> Could someone explain why the third method is considered to be more
> specific in this case?


Around methods are run first.
The primary methods.

Called is four than three.
Three has no call-next-method, so nothing else gets called.

If three had a call to CALL-NEXT-METHOD, next would be two.

-- 
http://lispm.dyndns.org
From: Slava Akhmechet
Subject: Re: Method combination problem
Date: 
Message-ID: <87k5vf9o66.fsf@gmail.com>
Rainer Joswig <······@lisp.de> writes:

> Around methods are run first.
> The primary methods.
Right, but in this case:

>> (defmethod foo ((a standard-object))
>>   2)
>> 
>> (defmethod foo :around (a)
>>   3)
>> 
>> (defmethod foo :around ((a standard-object))
>>   (call-next-method a))

Wouldn't it make sense for the first method to be more specific than
the second one, since it specializes on the type, while the around
method does not? Or is it the case that around methods *always* take
precedence, regardless of type specialization? If so, why?

-- 
Regards,
Slava Akhmechet.
From: Joe Marshall
Subject: Re: Method combination problem
Date: 
Message-ID: <1178910812.381472.59760@u30g2000hsc.googlegroups.com>
> Or is it the case that around methods *always* take
> precedence, regardless of type specialization? If so, why?

The around methods are always run first regardless.  If they didn't,
they wouldn't be `around' the primary methods.
From: Rainer Joswig
Subject: Re: Method combination problem
Date: 
Message-ID: <joswig-F7D829.21385111052007@news-europe.giganews.com>
In article <··············@gmail.com>,
 Slava Akhmechet <·········@gmail.com> wrote:

> Rainer Joswig <······@lisp.de> writes:
> 
> > Around methods are run first.
> > The primary methods.
> Right, but in this case:
> 
> >> (defmethod foo ((a standard-object))
> >>   2)
> >> 
> >> (defmethod foo :around (a)
> >>   3)
> >> 
> >> (defmethod foo :around ((a standard-object))
> >>   (call-next-method a))
> 
> Wouldn't it make sense for the first method to be more specific than
> the second one, since it specializes on the type, while the around
> method does not? Or is it the case that around methods *always* take
> precedence, regardless of type specialization? If so, why?



There several types of methods in standard method combination.

* around methods
* before methods
* primary methods
* after methods


around, before and after methods are there to add/modify to
primary methods.

There is a standard way how standard method combination works.

1) find all applicable methods for the arguments
2) sort them with a defined algorithm
3) create the effective method
4) call the effective method with the arguments

For all above method types there can be several applicable.
Precedence is determined for each method type locally.
So around methods always take precedence over primary methods.
That's why they are called 'around'.

around method 1
  around method n, via CALL-NEXT-METHOD
    before method 1, via CALL-NEXT-METHOD
      before method n
        primary method 1
         (primary method n, via CALL-NEXT-METHOD)
      after method 1
    after method 2
  around method n, returned from CALL-NEXT-METHOD
around method 1, returned from CALL-NEXT-METHOD

-- 
http://lispm.dyndns.org
From: Pascal Costanza
Subject: Re: Method combination problem
Date: 
Message-ID: <5ak1r0F2mce3lU2@mid.individual.net>
Rainer Joswig wrote:

> There is a standard way how standard method combination works.

Of course, there is a way to define other method combinations where you 
can change this. See define-method-combination.

But most of the time, the standard combination is fine.

Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Tim Bradshaw
Subject: Re: Method combination problem
Date: 
Message-ID: <f22k4p$kif$1$8300dec7@news.demon.co.uk>
On 2007-05-11 21:26:08 +0100, Pascal Costanza <··@p-cos.net> said:

> Of course, there is a way to define other method combinations where you 
> can change this. See define-method-combination.

I don't want to blow my own trumpet, but since the OP was asking about 
around methods, it might be worth their while looking at this: 
http://www.tfeb.org/lisp/hax.html#WRAPPING-STANDARD which give an 
example of a method combination which does what around methods do, but 
backwards (most-specific innermost).
From: Pascal Costanza
Subject: Re: Method combination problem
Date: 
Message-ID: <5ak4k7F2pc7s0U1@mid.individual.net>
Tim Bradshaw wrote:
> On 2007-05-11 21:26:08 +0100, Pascal Costanza <··@p-cos.net> said:
> 
>> Of course, there is a way to define other method combinations where 
>> you can change this. See define-method-combination.
> 
> I don't want to blow my own trumpet, but since the OP was asking about 
> around methods, it might be worth their while looking at this: 
> http://www.tfeb.org/lisp/hax.html#WRAPPING-STANDARD which give an 
> example of a method combination which does what around methods do, but 
> backwards (most-specific innermost).

Well, at least that's better than advertising F#. ;)


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Dan Bensen
Subject: Re: Method combination problem
Date: 
Message-ID: <f25d8o$a0a$1@wildfire.prairienet.org>
Slava Akhmechet wrote:
> Wouldn't it make sense for the first method to be more specific than
> the second one, since it specializes on the type, while the around
> method does not? Or is it the case that around methods *always* take
> precedence, regardless of type specialization? If so, why?

I don't know what the reason is, but around methods do take precedence:
http://www.lisp.org/HyperSpec/Body/sec_7-6-6-2.html
 > If there are any around methods, the most specific around method
 > is called.
 > An around method specifies code that is to be run instead of other
 > applicable methods, but which might contain explicit code which calls
 > some of those shadowed methods (via call-next-method).

-- 
Dan
www.prairienet.org/~dsb/
From: Kent M Pitman
Subject: Re: Method combination problem
Date: 
Message-ID: <uejlly0h6.fsf@nhplace.com>
Dan Bensen <··········@cyberspace.net> writes:

> Slava Akhmechet wrote:
> > Wouldn't it make sense for the first method to be more specific than
> > the second one, since it specializes on the type, while the around
> > method does not? Or is it the case that around methods *always* take
> > precedence, regardless of type specialization? If so, why?
> 
> I don't know what the reason is, but around methods do take precedence:
> http://www.lisp.org/HyperSpec/Body/sec_7-6-6-2.html

CLOS was constructed entirely separately from the rest of the standard
and kind of dropped in place.  I didn't see the discussion on it as it
was being incrementally developed, so have little first-hand information
on design discussions to offer.

However, intuitively, this is what I have always assumed that :AROUND
methods have to go around other methods, or else the will not be able
to do the things around methods are intended for (which is not
illustrated in these examples):

 * Bind a variable AROUND a computation.  If you put them inside, 
   would not be around.
     (let ((*something* ...)) (call-next-method))

 * Arrange for other pre- and post-conditions that for some reason need
   to precede :around methods for parent classes or need to be separated
   from before/after methods.  (This is kind of kludgey, but it does
   happen.)

 * Abort a computation prior to it happening.
     (check-something) (call-next-method)
  
 * Post-process a result.
     (let ((something (call-next-method))) (foo something))

If you assume this, you'll see they cannot go second.  Or else some
of these operations would go in the wrong place.  You don't want to
interleave the starting of the computation with other pre-tests or 
outer tests.  You want all of the pre-condition checks to happen first.
You want all of the environment binding things to happen around all
of the action.  And so on.

These :AROUND methods don't exist for the purpose of writing trivial
examples like the one you've chosen (presumably just as a test).  They
exist for writing modular code that does things like:

 (defmethod lift-object :around ((obj locked-object))
   (with-object-unlocked obj
     (call-next-method)))

My guess is that if you showed a real set of methods in play where the
wrong effect was happening, it would be easier to debug what your real
problem was.  And I suspect the answer would be that you hadn't really
designed your classes to be properly modular, though I'm speaking in
sweeping generalizations; it's hard to be more specific without seeing
concrete details.

If you assume that each object contributes modular behavior in this
way, then the only business of each method is to set up the context in
which it is to be used, not to really ask questions about what its
neighbors will do.  It is sufficient for :around methods on
locked-object to know that it happens _around_ anything that is an
inherited class, and certainly around all the primary methods.

In my experience, :around methods are a pain to override from a
subclass, and for this reason I recommend not using them for anything
you might ever conceivably want to override.  That is, don't do
something like (let ((*print-level* 7)) ...)  unless you're really
quite sure you don't want to be able to override that.  The example I
gave above, with a locked object, is a better example. It's unlikely
you'd want to lift a (hypothetical) locked object by doing other than
unlocking it (for whatever that might mean in this hypothetical
example), so it's usually fine to use :around methods for something
like that.

So mostly my personal recommendation is just to hold them in reserve,
know they're there, and use them when you can't find another way--not
just as a lifestyle choice.  The situations that call for them will
usually be obvious.  It's been quite a while since I used them myself,
but in my experience some domains are heavily mix-and-match and call
for them more, and others are not and rarely need them.  So the
experience of others might be quite different than mine depending on
what they're doing.
From: Dan Bensen
Subject: Re: Method combination problem
Date: 
Message-ID: <f2aj17$edu$1@wildfire.prairienet.org>
>> Slava Akhmechet wrote:
>>> Wouldn't it make sense for the first method to be more specific than
>>> the second one, since it specializes on the type, while the around
>>> method does not? Or is it the case that around methods *always* take
>>> precedence, regardless of type specialization? If so, why?

 > Dan Bensen <··········@cyberspace.net> writes:
>> I don't know what the reason is, but around methods do take precedence:
>> http://www.lisp.org/HyperSpec/Body/sec_7-6-6-2.html

Kent M Pitman wrote:
> ... intuitively, this is what I have always assumed that
> :AROUND methods have to go around other methods
>  * Bind a variable AROUND a computation.  ...
>  * Arrange for other pre- and post-conditions  ...
>  * Abort a computation prior to it happening. ...
>  * Post-process a result. ...

Thanks.  I hope the OP got what he was looking for out of the thread.

-- 
Dan
www.prairienet.org/~dsb/
From: Ken Tilton
Subject: Re: Method combination problem
Date: 
Message-ID: <2452i.36$md5.10@newsfe12.lga>
Dan Bensen wrote:
>>> Slava Akhmechet wrote:
>>>
>>>> Wouldn't it make sense for the first method to be more specific than
>>>> the second one, since it specializes on the type, while the around
>>>> method does not? Or is it the case that around methods *always* take
>>>> precedence, regardless of type specialization? If so, why?
> 
> 
>  > Dan Bensen <··········@cyberspace.net> writes:
> 
>>> I don't know what the reason is, but around methods do take precedence:
>>> http://www.lisp.org/HyperSpec/Body/sec_7-6-6-2.html
> 
> 
> Kent M Pitman wrote:
> 
>> ... intuitively, this is what I have always assumed that
>> :AROUND methods have to go around other methods
>>  * Bind a variable AROUND a computation.  ...
>>  * Arrange for other pre- and post-conditions  ...
>>  * Abort a computation prior to it happening. ...
>>  * Post-process a result. ...
> 
> 
> Thanks.  I hope the OP got what he was looking for out of the thread.
> 

Unfortunately I still do not understand the question, and I am a frickin 
genius, I have a three-digit IQ, 50% more than 2.

As far as I can make out the question has gotten even dumber during this 
thread, thanks mostly to your clarifications, leaving me wondering why 
:before methods run before primary methods, and why unspecific before 
methods do not get invoked after more specific primary methods.

I think the best thing to do is change :around to :xyz, :before to 
:qwerty, and :after to :tgif. Then the doc will say :xyz's work like 
this, :qwerty's work like this, etc etc, and no one will have a problem.

All those in favor, say "42".

:)

hth,kzo

ps. Anyone got an appropriate quotation in re the content of names? k

-- 
http://www.theoryyalgebra.com/

"Algebra is the metaphysics of arithmetic." - John Ray

"As long as algebra is taught in school,
there will be prayer in school." - Cokie Roberts

"Stand firm in your refusal to remain conscious during algebra."
    - Fran Lebowitz

"I'm an algebra liar. I figure two good lies make a positive."
    - Tim Allen
From: Dan Bensen
Subject: Re: Method combination problem
Date: 
Message-ID: <f2avjj$ib9$1@wildfire.prairienet.org>
 >>>> I don't know what the reason is, but around methods do take
 >>>> precedence:
 >>>> http://www.lisp.org/HyperSpec/Body/sec_7-6-6-2.html

 >> Kent M Pitman wrote:
 >>> ... intuitively, this is what I have always assumed that
 >>> :AROUND methods have to go around other methods
 >>>  * Bind a variable AROUND a computation.  ...
 >>>  * Arrange for other pre- and post-conditions  ...
 >>>  * Abort a computation prior to it happening. ...
 >>>  * Post-process a result. ...

 > Dan Bensen wrote:
 >> Thanks.  I hope the OP got what he was looking for out of the thread.

Ken Tilton wrote:
 > Unfortunately I still do not understand the question, and I am a
 > frickin genius, I have a three-digit IQ, 50% more than 2.
You are a genius, Ken, and I just want to say that each and every
one of us here on c.l.l is grateful for your presence and insightful
remarks.

However, apparently Kent's even smarter than you, because he
figured it out pretty darn quickly.

 > As far as I can make out the question has gotten even dumber
 > during this thread, thanks mostly to your clarifications
You're welcome.

 > leaving me wondering why :before methods run before primary methods,
Hmm.  That question never occurred to me.

 > and why unspecific before methods do not get invoked after
 > more specific primary methods.
I didn't think of that one either, but it's intriguing.  What if
the convention was to just call all methods in some predetermined
order?  Then there would be no need for call-next-method.

 > I think the best thing to do is change :around to :xyz, :before to
 > :qwerty, and :after to :tgif.
That's confusing.  They're not in alphabetical order.  They're not
ordered by string length either.  Oh wait, it's alphabetical by
last character.  Okay, I understand.

 > ps. Anyone got an appropriate quotation in re the content of names?
Sorry.  All I can think of is something starting with "A method by any
other name ...".

-- 
Dan
www.prairienet.org/~dsb/
From: Ken Tilton
Subject: Re: Method combination problem
Date: 
Message-ID: <q8q1i.30$_C3.15@newsfe12.lga>
Slava Akhmechet wrote:
> Rainer Joswig <······@lisp.de> writes:
> 
> 
>>Around methods are run first.
>>The primary methods.
> 
> Right, but in this case:
> 
> 
>>>(defmethod foo ((a standard-object))
>>>  2)
>>>
>>>(defmethod foo :around (a)
>>>  3)
>>>
>>>(defmethod foo :around ((a standard-object))
>>>  (call-next-method a))
> 
> 
> Wouldn't it make sense for the first method to be more specific..

Here is your problem. You have fixated on this "specific" thing, as if 
that is all there is to CLOS dispatch. There is quite a bit more.

  than
> the second one, since it specializes on the type, while the around
> method does not? Or is it the case that around methods *always* take
> precedence, regardless of type specialization?

Hunh? You have an "or" where "and" should be. Around methods go first, 
and within the set of applicable around methods, the most-specific type 
specialization goes first.

> If so, why?
> 

(a) Hunh? that's how they coded CLOS. Maybe you mean...
(b) Why did they code CLOS this way? Think about it. A more specific 
type will have unique rquirements not held by the more general type of 
which it is a subtype. It can only be sure of controlling what code runs 
by being given control first, so it can make its own special decisions 
about what should happen given the input arguments.

hth, kxo


-- 
http://www.theoryyalgebra.com/

"Algebra is the metaphysics of arithmetic." - John Ray

"As long as algebra is taught in school,
there will be prayer in school." - Cokie Roberts

"Stand firm in your refusal to remain conscious during algebra."
    - Fran Lebowitz

"I'm an algebra liar. I figure two good lies make a positive."
    - Tim Allen
From: Dan Bensen
Subject: Re: Method combination problem
Date: 
Message-ID: <f25e0q$a7k$1@wildfire.prairienet.org>
Ken Tilton wrote:
> Slava Akhmechet wrote:
>> If so, why?
> (b) Why did they code CLOS this way? Think about it. A more specific 
> type will have unique rquirements not held by the more general type of 
> which it is a subtype.

The "if so, why?" question doesn't refer to more type-specific methods.
It refers to non-type-specific around methods:

Slava Akhmechet wrote:
 > Or is it the case that around methods *always* take
 > precedence, regardless of type specialization? If so, why?

Why do less type-specific around methods take precedence over
more type-specific non-around methods?

 > (a) Hunh? that's how they coded CLOS.

And anyone with a 2-digit IQ can figure out that question (b)
is implied.

-- 
Dan
www.prairienet.org/~dsb/
From: Tim Bradshaw
Subject: Re: Method combination problem
Date: 
Message-ID: <f275mk$86r$1$830fa7a5@news.demon.co.uk>
On 2007-05-12 23:16:13 +0100, Dan Bensen <··········@cyberspace.net> said:

> Why do less type-specific around methods take precedence over
> more type-specific non-around methods?

Around methods run most-specific outermost: that's how they're defined. 
 It is very easy to define an alternative method combination which has 
a method type which run least-specific outermost.  That's exactly what 
wrapping methods are in the page I referenced earlier.
From: Thomas A. Russ
Subject: Re: Method combination problem
Date: 
Message-ID: <ymi3b1zxs72.fsf@sevak.isi.edu>
Dan Bensen <··········@cyberspace.net> writes:

> Ken Tilton wrote:
> > Slava Akhmechet wrote:
> >> If so, why?
> > (b) Why did they code CLOS this way? Think about it. A more specific
> > type will have unique rquirements not held by the more general type of
> > which it is a subtype.
> 
> 
> The "if so, why?" question doesn't refer to more type-specific methods.
> It refers to non-type-specific around methods:
> 
> Slava Akhmechet wrote:
>  > Or is it the case that around methods *always* take
>  > precedence, regardless of type specialization? If so, why?
> 
> Why do less type-specific around methods take precedence over
> more type-specific non-around methods?

Because the method combination rules specify that ALL around methods run
before ANY primary methods.  The reason is that, otherwise, they
wouldn't be AROUND methods in the sense of surrounding calls to the
primary methods.

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Rainer Joswig
Subject: Re: Method combination problem
Date: 
Message-ID: <joswig-CF43E7.20552811052007@news-europe.giganews.com>
In article <····························@news-europe.giganews.com>,
 Rainer Joswig <······@lisp.de> wrote:

> In article <··············@gmail.com>,
>  Slava Akhmechet <·········@gmail.com> wrote:
> 
> > I have a problem with CLOS method combination. Perhaps it's because of
> > a misunderstanding. I have the following setup:
> > 
> > (defgeneric foo (a))
> > 
> > (defmethod foo (a)
> >   1)
> > 
> > (defmethod foo ((a standard-object))
> >   2)
> > 
> > (defmethod foo :around (a)
> >   3)
> > 
> > (defmethod foo :around ((a standard-object))
> >   (call-next-method a))
> > 
> > It appears that if I make the following call:
> > 
> > (foo some-standard-object)
> > 
> > The expression evaluated to 3, which means that the next most specific
> > method for 'foo' is the third one, not the second one as I would
> > expect (I expected the expression to return 2). I run into this in
> > SBCL and OpenMCL which suggests that the problem here is my
> > misunderstanding of the issue.
> > 
> > Could someone explain why the third method is considered to be more
> > specific in this case?
> 
> 
> Around methods are run first.
> The primary methods.
> 
> Called is four than three.
> Three has no call-next-method, so nothing else gets called.
> 
> If three had a call to CALL-NEXT-METHOD, next would be two.

Around methods are run first.
Then primary methods.

Called is four (around method) than three (next around method).
Three has no call to call-next-method, so nothing else gets called.

If three had a call to CALL-NEXT-METHOD, next would be two.

-- 
http://lispm.dyndns.org