From: Aaron Gross
Subject: Question about EQL parameter specializer and object extent
Date: 
Message-ID: <lyd5wwqdmc.fsf@circe.aeaea>
I've got some questions about the use of DEFMETHOD.  Recently I found
myself wanting to do something like this:

;;; simplified example
(let ((my-foo (make-instance 'foo ...)))
  (defmethod baz ((arg (eql my-foo)))
     (do-something some-free-variable))
  (bar my-foo))

The idea is that calling the method BAR on a temporary instance of FOO
gives us just what we need here, except that BAR ultimately calls some
existing method BAZ defined on class FOO, and we need to change the
behavior of BAZ in this special case to do something else, the
something else involving a free variable.

Ignoring clean-up for the moment (about that see below), I tried this
and it seems to do exactly what I want.  Some questions:

1. Is this bad style (again, clean-up issues aside for the moment)?
Does the fact that I even want to do something like this show some
really fundamental mis-understanding?

2. If it's not good style, then how should I do what I'm trying to do?
I could always do something like this:

(defclass ad-hoc (foo)
  ((some-extra-variable :initarg :extra)))
(defmethod baz ((arg ad-hoc))
  (do-something (slot-value arg 'some-extra-variable)))
(let ((my-foo (make-instance 'ad-hoc :extra some-free-variable)))
  (bar my-foo))

This looks a lot uglier than what I wanted to do above.  After all,
I'm defining a subclass AD-HOC whose only purpose is to sneak some
otherwise free variable into the new BAZ method.  That looks
absolutely C++ish.  If I want to specialize a method on an object, and
if DEFMETHOD lets me do just that, then creating a class to do it is
just plain ugly.

3. Now, clean-up.  This seems to be the crucial point here.  Seems to
me that the MY-FOO object will never get garbage collected, because
it's referred to by the BAZ method -- which we want removed anyway.  I
could just do a REMOVE-METHOD on this specialized BAZ in an
UNWIND-PROTECT, then let the MY-FOO object get garbage collected, and
everything would be fine -- in my *particular* case.  But that
wouldn't work in general, because some code deep inside of
DO-SOMETHING could, say, bind some special variable to the MY-FOO
object (thus prolonging its extent) and then re-define BAZ specialized
to that object -- a BAZ method that they presumably *don't* want
removed.  So it seems out of the question to write, say, a
WITH-METHODS macro that would remove the method at the end, because
how would it know that it's OK to remove the method?

On the other hand, this whole question is independent of the Lisp
language specification, right?  Could a Lisp implementation
automatically remove a method once it can no longer be invoked?  Or
does that somehow violate the specification?

From: Kenny Tilton
Subject: Re: Question about EQL parameter specializer and object extent
Date: 
Message-ID: <5bVzd.38093$ld2.15819274@twister.nyc.rr.com>
Aaron Gross wrote:
> I've got some questions about the use of DEFMETHOD.  Recently I found
> myself wanting to do something like this:
> 
> ;;; simplified example
> (let ((my-foo (make-instance 'foo ...)))
>   (defmethod baz ((arg (eql my-foo)))
>      (do-something some-free-variable))
>   (bar my-foo))
> 
> The idea is that calling the method BAR on a temporary instance of FOO
> gives us just what we need here, except that BAR ultimately calls some
> existing method BAZ defined on class FOO, and we need to change the
> behavior of BAZ in this special case to do something else, the
> something else involving a free variable.
> 
> Ignoring clean-up for the moment (about that see below), I tried this
> and it seems to do exactly what I want.  Some questions:
> 
> 1. Is this bad style (again, clean-up issues aside for the moment)?
> Does the fact that I even want to do something like this show some
> really fundamental mis-understanding?

It is hard to say because, sensibly enough, the above example was 
simplified to highlight certain essentials. But I suspect a deeper fix 
will obviate the need for this action-at-a-distance ad hoc method 
definition.

I see it this way. There is this nice little foo/bar/baz mechanism 
which, at the point above, is discovered by the developer to have broken 
down. Happens to me all the time. I always take it as a Message From God 
to refactor the whole mess. You consider that:

> 
> 2. If it's not good style, then how should I do what I'm trying to do?
> I could always do something like this:
> 
> (defclass ad-hoc (foo)
>   ((some-extra-variable :initarg :extra)))
> (defmethod baz ((arg ad-hoc))
>   (do-something (slot-value arg 'some-extra-variable)))
> (let ((my-foo (make-instance 'ad-hoc :extra some-free-variable)))
>   (bar my-foo))
> 
> This looks a lot uglier than what I wanted to do above.  After all,
> I'm defining a subclass AD-HOC whose only purpose is to sneak some
> otherwise free variable into the new BAZ method.  That looks
> absolutely C++ish.  If I want to specialize a method on an object, and
> if DEFMETHOD lets me do just that, then creating a class to do it is
> just plain ugly.

Tilton's Law: "The first time you need something is just the first time 
you need it."

ie, Assuming some-other-variable is not itself a mistaken addition 
because of some other mis-analysis, class FOO should have had that slot 
all along and this is just the first time in the use of FOO that the gap 
has been exposed by the requirements placed on FOO by the application. 
There will be more times. (aside: maybe they have already come up and 
been kludged away by something such as the ad hoc method approach.)

anyway, add the slot to foo and you will probably need it again 
tomorrow, or discover that it solves other known problems. even if not, 
solving only one problem does not necessarily make something a bad fix. 
I have another law for that, but I will spare you.

otoh, possibly bar needs a new parameter, or if the action-at-a-distance 
is justified, perhaps you need a special variable, ie, a dedicated 
with-some-other-variable macro instead of a with-method.

again, without seeing the semantics befind foo/bar/baz this is all just 
guesswork.

kenny


-- 
Cells? Cello? Celtik?: http://www.common-lisp.net/project/cells/
Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
From: Aaron Gross
Subject: Re: Question about EQL parameter specializer
Date: 
Message-ID: <lyk6r2l61j.fsf@circe.aeaea>
Kenny Tilton <·······@nyc.rr.com> writes:

> I see it this way. There is this nice little foo/bar/baz mechanism
> which, at the point above, is discovered by the developer to have
> broken down. Happens to me all the time.  I always take it as a
> Message From God to refactor the whole mess.

Happens a lot to me too, but not this time -- I think.  In this case,
there's this nice little FOO-BAR mechanism that, hey, look, does just
what we want (the Right Way, not kludgily) in this new situation --
*if* we just override that BAZ thing.

> Tilton's Law: "The first time you need something is just the first
> time you need it."

Good point.  But see below...

> ie, Assuming some-other-variable is not itself a mistaken addition 
> because of some other mis-analysis, class FOO should have had that slot 
> all along and this is just the first time in the use of FOO that the gap 
> has been exposed by the requirements placed on FOO by the application. 
> There will be more times. (aside: maybe they have already come up and 
> been kludged away by something such as the ad hoc method approach.)
> 
> anyway, add the slot to foo and you will probably need it again 
> tomorrow, or discover that it solves other known problems. even if not, 
> solving only one problem does not necessarily make something a bad fix. 
> I have another law for that, but I will spare you.

Let's call BAZ specialized to class FOO the "default behavior", and
call our specialization of BAZ to some object "customization".  "Aha",
I hear you say, "that makes it all the more clear: If you want to
customize BAZ now, then that indicates that BAZ should have been
customizable from the very beginning".

My reply: Yes, I've always known that BAZ should be customizable.  And
it always has been, because it's a *generic function*.  (I should add
that writing your own BAZ method would be trivial in this case.)
Maybe I just have a minimalist philosophy, but I want to supply a
reasonable default BAZ for class FOO, and if the user wants to
customize it, fine, that's why God created polymorphism.

Anyway, that seems to be the essence of your objection -- not
action-at-a-distance (an apt phrase, by the way) or WITH-METHODS
macros or anything else.  Does one enable customization in the
"original" method, or does one just let the user customize via a new
method?

If the former, then we add the extra slot to FOO and uglify the BAZ
method on FOO to use that slot when it's bound.  But there's always a
cost to adding slots to classes, in terms of increased clutter and
complexity.

If the latter alternative, then the typical way to customize would be
to define a subclass of FOO, then customize BAZ on that.  Then for my
example, we'd then make a temporary instance of that subclass, etc.
But why should we make such a crude customization when we don't have
to?  We can get the same effect with a short, sharp shock: by
specializing only on the temporary instance itself.

> otoh, possibly bar needs a new parameter, or if the
> action-at-a-distance is justified, perhaps you need a special
> variable, ie, a dedicated with-some-other-variable macro instead of
> a with-method.

In this particular case, the extra parameter would more naturally be
an extra slot in class FOO than an extra argument to BAZ.  But even if
it were more natural to put the parameter with method BAR than with
class FOO, I'd still have basically the same objections as above.  And
also, as I said in another post, using a special variable seems out of
the question since it affects BAZ on every instance of FOO, not just
the temporary instance I want to customize.

Bottom line, I think the real alternative at issue here is just doing
either what I suggested, or going back and adding the extra slot to
the original FOO the way you suggested initially.  In this example it
happens to be trivially easy to override the "default" behavior of BAZ
with a new method, so I still prefer that way of customizing.  That's
aside from other valid objections that have been raised, such as not
wanting to call DEFMETHOD at run time.

> again, without seeing the semantics befind foo/bar/baz this is all
> just guesswork.

Well, now I've gone and said that BAZ specialized to FOO is the
"default behavior" (which anyone might want to customize) and that BAZ
specialized to the temporary instance of FOO is "custom" behavior, so
presumably that strengthens your initial opinion.
From: Kenny Tilton
Subject: Re: Question about EQL parameter specializer
Date: 
Message-ID: <zogAd.34127$kq2.15594@twister.nyc.rr.com>
Aaron Gross wrote:
> Kenny Tilton <·······@nyc.rr.com> writes:
> 
> 
>>I see it this way. There is this nice little foo/bar/baz mechanism
>>which, at the point above, is discovered by the developer to have
>>broken down. Happens to me all the time.  I always take it as a
>>Message From God to refactor the whole mess.
> 
> 
> Happens a lot to me too, but not this time -- I think.  In this case,
> there's this nice little FOO-BAR mechanism that, hey, look, does just
> what we want (the Right Way, not kludgily) in this new situation --
> *if* we just override that BAZ thing.

That "if we just override..." is what I mean by foo-bar being broken. 
Somehow baz will not do the Right Thing given the rest of the design. It 
needs more information, or (your solution) we must engage in 
self-modifying code. With your solution, BAZ gets tweaked for all 
instances processed by this bit of code, and only while this bot of code 
is executing. You tout the trivial ease of your hack, but that just 
reflects the Unbearable Awesome Powerfulness of Lisp and CLOS.

>>again, without seeing the semantics befind foo/bar/baz this is all
>>just guesswork.
> 
> 
> Well, now I've gone and said that BAZ specialized to FOO is the
> "default behavior" (which anyone might want to customize) and that BAZ
> specialized to the temporary instance of FOO is "custom" behavior, so
> presumably that strengthens your initial opinion.

But I still do not see the semantics, so I am still guessing. I wager an 
opportunity for a Deeper Fix is being missed because you have fallen in 
love with this hack. But I am a romantic, so i say, Go for it!

kenny


-- 
Cells? Cello? Celtik?: http://www.common-lisp.net/project/cells/
Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
From: Aaron Gross
Subject: Re: Question about EQL parameter specializer
Date: 
Message-ID: <lypt0sgo7f.fsf@circe.aeaea>
Kenny Tilton <·······@nyc.rr.com> writes:

> But I still do not see the semantics, so I am still guessing. I
> wager an opportunity for a Deeper Fix is being missed because you
> have fallen in love with this hack. But I am a romantic, so i say,
> Go for it!

Well, another Romantic once declared,

    We can forgive a man for making a useful thing as long as he does
    not admire it.  The only excuse for making a useless thing is that
    one admires it intensely.

But as I said in another post, I'm convinced now that my trick was
useless and I no longer admire it.  Ergo there was no excuse for
making it.

Regarding the semantics of the original example, I was actually going
to give an analogy just overflowing with semantics right here (I had
even typed it out), but now having read Peter Seibel's post and being
convinced that I should have defined a subclass, the question is moot.
From: Kenny Tilton
Subject: Re: Question about EQL parameter specializer
Date: 
Message-ID: <kaVAd.34629$kq2.8731@twister.nyc.rr.com>
Aaron Gross wrote:
> Kenny Tilton <·······@nyc.rr.com> writes:
> 
> 
>>But I still do not see the semantics, so I am still guessing. I
>>wager an opportunity for a Deeper Fix is being missed because you
>>have fallen in love with this hack. But I am a romantic, so i say,
>>Go for it!
> 
> 
> Well, another Romantic once declared,
> 
>     We can forgive a man for making a useful thing as long as he does
>     not admire it.  The only excuse for making a useless thing is that
>     one admires it intensely.
> 
> But as I said in another post, I'm convinced now that my trick was
> useless and I no longer admire it.  Ergo there was no excuse for
> making it.
> 
> Regarding the semantics of the original example, I was actually going
> to give an analogy just overflowing with semantics right here (I had
> even typed it out), but now having read Peter Seibel's post and being
> convinced that I should have defined a subclass, the question is moot.

Nope, now the question is, do you really need a subclass? Your first 
instinct not to proliferate classes needlessly, was a good one. This is 
why OO failed as a silver bullet--every time some exception comes along 
one ends up creating a new class. The code works but becomes the moral 
equivalent of spaghetti code--it works because of this patch and that 
patch, a subclass here, an around method there, etc etc.

Should foo have that slot, with most instances having the initform 
default in there or the slot unbound? Do bar and baz need another 
argument? Does baz /really/ need that extra bit of info? Does the whole 
thing need refactoring?

Unfortunately we still do not know the semantics, tho I almost goaded 
you into disclosing it last time.

:)

kenny


-- 
Cells? Cello? Celtik?: http://www.common-lisp.net/project/cells/
Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
From: Thomas F. Burdick
Subject: Re: Question about EQL parameter specializer
Date: 
Message-ID: <xcvsm5ninzz.fsf@conquest.OCF.Berkeley.EDU>
Kenny Tilton <·······@nyc.rr.com> writes:

> Aaron Gross wrote:
>
> > Regarding the semantics of the original example, I was actually going
> > to give an analogy just overflowing with semantics right here (I had
> > even typed it out), but now having read Peter Seibel's post and being
> > convinced that I should have defined a subclass, the question is moot.
> 
> Nope, now the question is, do you really need a subclass? Your first 
> instinct not to proliferate classes needlessly, was a good one. This is 
> why OO failed as a silver bullet--every time some exception comes along 
> one ends up creating a new class. The code works but becomes the moral 
> equivalent of spaghetti code--it works because of this patch and that 
> patch, a subclass here, an around method there, etc etc.
> 
> Should foo have that slot, with most instances having the initform 
> default in there or the slot unbound? Do bar and baz need another 
> argument? Does baz /really/ need that extra bit of info? Does the whole 
> thing need refactoring?

Looking at the original post, it looks like the kind of thing where
the answer is to add a keyword argument to bar:

(let ((my-foo (make-instance 'foo ...)))
  (labels ((my-baz (arg) (do-something some-var)))
    (bar my-foo :baz #'my-baz)))

But of course, I can't say for sure, because ...

> Unfortunately we still do not know the semantics, tho I almost goaded 
> you into disclosing it last time.

... the example given is a great argument for using the traditional,
corny style for OO examples, at a minimum.
From: Aaron Gross
Subject: Re: Question about EQL parameter specializer
Date: 
Message-ID: <lyu0q0dpi0.fsf@circe.aeaea>
Kenny Tilton <·······@nyc.rr.com> writes:

> Aaron Gross wrote:
> > 
> > Regarding the semantics of the original example, I was actually
> > going to give an analogy just overflowing with semantics right
> > here (I had even typed it out), but now having read Peter Seibel's
> > post and being convinced that I should have defined a subclass,
> > the question is moot.
> 
> Nope, now the question is, do you really need a subclass? ...

> Unfortunately we still do not know the semantics, tho I almost goaded 
> you into disclosing it last time.

Everybody's jumping on my case now for not giving more semantic
context, so I'll address that.  There's a trick in mathematics: If
you're having trouble proving (or disproving) some proposition, try
generalizing the proposition -- abstracting out some of the details --
and proving that.  It's sometimes easier to prove a stronger statement
than a weaker statement entailed by it.

I suspected from the start that if there was something wrong with my
suggested hack, it was probably a "structural" problem.  If you and
others say you need more semantic context to criticize my hack, that's
fine, but Peter Seibel and Steven Haflich showed that the hack had
style problems on "structural" grounds alone, regardless of semantic
context.  They proved a stronger statement.

I had originally discounted the "subclass" idea on aesthetic grounds.
Once Peter Seibel corrected my taste by showing that it was my own
objection to defining a subclass which was invalid, the subclass
solution was put back in the game, and the question became fairly easy
for me to answer -- to my own satisfaction, after considering your
points, which were well-taken, and I know others might not like my
decision if they knew the semantic context, which they won't because
I've gotten a good answer already so nyah nyah.

That said, I think I've already obliged quite a lot semantics-wise by
saying that the method on the original class was reasonable *default*
behavior which was being *customized*, and also by saying a word or
two about customizing via inheritance/polymorphism.  (No one commented
on this.)  But all that was before I'd gotten a convincing answer
which proved that even that much additional semantic information was
not needed to show that my suggested hack was a Bad Thing.

Finally, I'd like to repeat that your points were well-taken, and I
appreciate everyone's responses; all were helpful, even including
those I rejected out of hand.
From: Thomas F. Burdick
Subject: Re: Question about EQL parameter specializer
Date: 
Message-ID: <xcvpt0nindl.fsf@conquest.OCF.Berkeley.EDU>
Aaron Gross <·······@bloomberg.com.invalid> writes:

> I had originally discounted the "subclass" idea on aesthetic grounds.
> Once Peter Seibel corrected my taste by showing that it was my own
> objection to defining a subclass which was invalid, the subclass
> solution was put back in the game, and the question became fairly easy
> for me to answer -- to my own satisfaction, after considering your
> points, which were well-taken, and I know others might not like my
> decision if they knew the semantic context, which they won't because
> I've gotten a good answer already so nyah nyah.

In case you weren't aware, usenet is not a fix-my-code for free
service.  There are all manner of reasons that people participate in
usenet discussions, but for those offering useful advice, some sort of
intellectual back and forth is generally the major motivator.  Being a
smug ass about having not provided enough detail for said participants
to feel like they could offer good thoughts is not a good way to
encourage people to continue to engage you.  Speaking personally,
you've just offered quite a disincentive to ever bother reading your posts.
From: Aaron Gross
Subject: Re: Question about EQL parameter specializer
Date: 
Message-ID: <lyis6eznvy.fsf@circe.aeaea>
···@conquest.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> In case you weren't aware, usenet is not a fix-my-code for free
> service.  There are all manner of reasons that people participate in
> usenet discussions, but for those offering useful advice, some sort
> of intellectual back and forth is generally the major motivator.
> Being a smug ass about having not provided enough detail for said
> participants to feel like they could offer good thoughts is not a
> good way to encourage people to continue to engage you.  Speaking
> personally, you've just offered quite a disincentive to ever bother
> reading your posts.

I am sorry that came across as smug.  I'd thought that I was kidding
with the other poster, but obviously it didn't come across that way.

Once again, though, in response to the request for semantic context, I
offered a reasonable amount, at least as a start.  I thought it was
quite to the point, but it was completely ignored.  You're still
ignoring it here.  And I've been doing that "intellectual back and
forth" thing on various sub-topics on this thread over the past week.
From: Kenny Tilton
Subject: Re: Question about EQL parameter specializer
Date: 
Message-ID: <ZDdCd.37065$kq2.32628@twister.nyc.rr.com>
Aaron Gross wrote:
> ···@conquest.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
> 
> 
>>In case you weren't aware, usenet is not a fix-my-code for free
>>service.  There are all manner of reasons that people participate in
>>usenet discussions, but for those offering useful advice, some sort
>>of intellectual back and forth is generally the major motivator.
>>Being a smug ass about having not provided enough detail for said
>>participants to feel like they could offer good thoughts is not a
>>good way to encourage people to continue to engage you.  Speaking
>>personally, you've just offered quite a disincentive to ever bother
>>reading your posts.
> 
> 
> I am sorry that came across as smug.  I'd thought that I was kidding
> with the other poster, but obviously it didn't come across that way.
> 
> Once again, though, in response to the request for semantic context, I
> offered a reasonable amount, at least as a start.  I thought it was
> quite to the point, but it was completely ignored.

No, i got a good laugh out of it. Reminded me of Lady Godiva's baring of 
her semantics. I was laughing for two reasons. The first was, Wow, would 
it not have been easier just to describe what you were up to than go 
thru a second distillation analysis? The second reason was that again 
trying to distill out what you conclude is noise utterly misses the 
point, which is that I for one suspected you might be missing a more 
fundamental design gaffe. Or even Yet Another Language Mechanics Gaffe. 
Now if -- if, I say -- you have a blindspot for something, then you are 
the last person to decide what is salient and what is not and the very 
effort to do so is, well, funny. It is well understood that explaining a 
stubborn problem to another developer usually helps the explainer find 
the problem without any input from the second developer. This is because 
we slow down and fill in all sorts of details for the person new to the 
problem, details we know are irrelevant to -- Oh, jeez! /That/ is the 
problem! Thanks for your help!

I also ignored your bad analogy about mathematical proof. A better 
analogy is a good hardware store, where certain questions will trigger a 
dubious "What do you want it for?". The clerk hears something in the 
question that tells them they might be able to offer better help if they 
knew what we were up to. Smart people answer the clerk's question.


So you have now gone through two distillations and now a lengthy thread 
rather than disclose what you are up to. This is fascinating like a 
train wreck, so I for one hope it goes on for weeks and, contra Thomas, 
will certainly read everything you post for a long time to come. :)

Let us try a simple compromise: what are the real names of foo, bar, and 
baz, and what names did you come up with for the subclass and the new 
slot in which to stuff that "something else" data? How about also the 
name of the local variable holding the "something else" value at the 
point where you are now executing (make-instance 'foo-sub?

>  And I've been doing that "intellectual back and
> forth" thing on various sub-topics on this thread over the past week.

I think it is just "forth and forth" when you do not answer good faith 
questions we ask about the problem for which with you are asking help.

:)

kenny

-- 
Cells? Cello? Celtik?: http://www.common-lisp.net/project/cells/
Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
From: Peter Seibel
Subject: Re: Question about EQL parameter specializer
Date: 
Message-ID: <m3oegc9a46.fsf@javamonkey.com>
Aaron Gross <·······@bloomberg.com.invalid> writes:

> If the latter alternative, then the typical way to customize would
> be to define a subclass of FOO, then customize BAZ on that. Then for
> my example, we'd then make a temporary instance of that subclass,
> etc. But why should we make such a crude customization when we don't
> have to? We can get the same effect with a short, sharp shock: by
> specializing only on the temporary instance itself.

Well, for one thing, presumably every time you come through this code
path you're going to have to add and then remove a method specialized
on the (new) temporary object. Assuming this code path will be
executed more than once what you're essentially saying is that there's
a subclass of FOO, namely the set of all the objects you're going to
instantiate at this point in the code, that are distinct from your
averager run-of-the-mill FOOs. So rather than leaving the readers of
your code wondering why you're doing this unusual hack of adding and
removing methods at runtime, just define a class and give it a good
name that reflects what's special about the FOOs instantiated at this
point in your code. Then, I imagine, some of Kenny's Laws will kick
in--you may discover that by the very act of naming the thing you'll
get some deeper insight into what's going on. Or you'll discover that
there's another place in your code that you should really be
instantiating this subclass instead of vanilla FOOs. In other words,
here's the advantages of just defining a sub-class:

  - Almost certainly more efficient at runtime.

  - Not fighting the language.

  - Gives you a chance to communicate, via the name of the subclass,
    what's special about these objects.

The one disadvantage is:

  - You have to define a new subclass.

I'm not sure I see that that disadvantage is worth giving up the
advantages.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Kenny Tilton
Subject: Re: Question about EQL parameter specializer
Date: 
Message-ID: <dsEAd.38598$ld2.16478722@twister.nyc.rr.com>
Peter Seibel wrote:
> Aaron Gross <·······@bloomberg.com.invalid> writes:
> 
> 
>>If the latter alternative, then the typical way to customize would
>>be to define a subclass of FOO, then customize BAZ on that. Then for
>>my example, we'd then make a temporary instance of that subclass,
>>etc. But why should we make such a crude customization when we don't
>>have to? We can get the same effect with a short, sharp shock: by
>>specializing only on the temporary instance itself.
> 
> 
> Well, for one thing, presumably every time you come through this code
> path you're going to have to add and then remove a method specialized
> on the (new) temporary object. Assuming this code path will be
> executed more than once what you're essentially saying is that there's
> a subclass of FOO, namely the set of all the objects you're going to
> instantiate at this point in the code, that are distinct from your
> averager run-of-the-mill FOOs. So rather than leaving the readers of
> your code wondering why you're doing this unusual hack of adding and
> removing methods at runtime, just define a class and give it a good
> name that reflects what's special about the FOOs instantiated at this
> point in your code. Then, I imagine, some of Kenny's Laws will kick
> in--you may discover that by the very act of naming the thing you'll
> get some deeper insight into what's going on. Or you'll discover that
> there's another place in your code that you should really be
> instantiating this subclass instead of vanilla FOOs. In other words,
> here's the advantages of just defining a sub-class:
> 
>   - Almost certainly more efficient at runtime.
> 
>   - Not fighting the language.
> 
>   - Gives you a chance to communicate, via the name of the subclass,
>     what's special about these objects.
> 
> The one disadvantage is:
> 
>   - You have to define a new subclass.
> 
> I'm not sure I see that that disadvantage is worth giving up the
> advantages.

(a) yes, I have refrained from invoking the spectre of being hunted down 
  and throttled by some future programmer when they discover this hack 
after several days of futile debugging.

(b) Kenny's Laws, instead of Tilton's? Leverage the brand, eh? But 
Tilton is so much more pompous, great for Laws. Hmmm....

(c) I have also refrained from mentioning Cells, partly because, absent 
the slightest clue yet as to the actual semantics, it is not clear they 
could offer the best of both worlds, viz., functionally different 
handling of an instance without subclassing.

(d) It is interesting that the OP has not divulged the semantics. I 
think that serves to keep the discussion at the level of language 
mechanics. Revealing the semantics would reveal, I wager, that none of 
this self-modifying code is necessary.

kenny
-- 
Cells? Cello? Celtik?: http://www.common-lisp.net/project/cells/
Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
From: Aaron Gross
Subject: Re: Question about EQL parameter specializer
Date: 
Message-ID: <lysm5ogoam.fsf@circe.aeaea>
Peter Seibel <·····@javamonkey.com> writes:

> Aaron Gross <·······@bloomberg.com.invalid> writes:
> 
> > If the latter alternative, then the typical way to customize would
> > be to define a subclass of FOO, then customize BAZ on that. Then
> > for my example, we'd then make a temporary instance of that
> > subclass, etc. But why should we make such a crude customization
> > when we don't have to? We can get the same effect with a short,
> > sharp shock: by specializing only on the temporary instance
> > itself.
> 
> Assuming this code path will be executed more than once what you're
> essentially saying is that there's a subclass of FOO, namely the set
> of all the objects you're going to instantiate at this point in the
> code, that are distinct from your averager run-of-the-mill FOOs.

Thanks, that's the best explanation I've heard yet: The subclass
wouldn't be a singleton, it would be a class which just happens to
have only a single instance at any given time.  I'm convinced now that
the Right Thing is to define a subclass.
From: Aaron Gross
Subject: Re: Question about EQL parameter specializer and object extent
Date: 
Message-ID: <lywtv3q5eb.fsf@circe.aeaea>
Aaron Gross <·······@bloomberg.com.invalid> writes:

> 3. Now, clean-up. ... But that wouldn't work in general, because some
> code deep inside of DO-SOMETHING could, say, bind some special
> variable to the MY-FOO object (thus prolonging its extent) and then
> re-define BAZ specialized to that object -- a BAZ method that they
> presumably *don't* want removed.  So it seems out of the question to
> write, say, a WITH-METHODS macro that would remove the method at the
> end, because how would it know that it's OK to remove the method?

Oops, sorry to follow up to my own post, but I just realized that this
wouldn't be a problem at all.  I'd forgotten that methods are objects.
So the WITH-METHODS macro would simply bind the method objects
themselves before evaluating the body, and then call REMOVE-METHOD on
those objects in an UNWIND-PROTECT clean-up.  So really the clean-up
is trivial and the question of object extent is irrelevant.

I guess, then, that my question reduces to style: Is it OK style to do
this WITH-METHODS kind of thing?  That is,

(let ((my-foo (make-instance 'foo ...)))
  (with-methods ((baz ((arg (eql my-foo)))
		      (do-something some-free-variable)))
    (bar my-foo)))
From: Wade Humeniuk
Subject: Re: Question about EQL parameter specializer and object extent
Date: 
Message-ID: <WKWzd.14944$uj2.13060@clgrps12>
Aaron Gross wrote:

> I've got some questions about the use of DEFMETHOD.  Recently I found
> myself wanting to do something like this:
> 
> ;;; simplified example
> (let ((my-foo (make-instance 'foo ...)))
>   (defmethod baz ((arg (eql my-foo)))
>      (do-something some-free-variable))
>   (bar my-foo))
> 


I think what you really want is a simple closure
along with a special variable:

(defvar *baz* nil)

(let* ((my-foo (make-instance 'foo ...))
        (*baz* (lambda (arg)
                 (do-some-stuff my-foo)
                 (do-something some-free-variable))))
   (declare (dynamic-extent *baz*))
   (bar my-foo)))

Then bar calls *baz* with:

(funcall *baz* arg)

Creating a closure like this is very fast and does not
need to invoke all the machinery of creating and removing a
method.  Also special variables are used to pass "extra"
args to functions.

This
From: Aaron Gross
Subject: Re: Question about EQL parameter specializer
Date: 
Message-ID: <lymzvyl63y.fsf@circe.aeaea>
Wade Humeniuk <····················@telus.net> writes:

> I think what you really want is a simple closure along with a
> special variable:
> 
> (defvar *baz* nil)
> 
> (let* ((my-foo (make-instance 'foo ...))
>         (*baz* (lambda (arg)
>                  (do-some-stuff my-foo)
>                  (do-something some-free-variable))))
>    (declare (dynamic-extent *baz*))
>    (bar my-foo)))
> 
> Then bar calls *baz* with:

A typo, I think: BAZ, not BAR.
 
> (funcall *baz* arg)

When you bind *BAZ* you're changing the behavior of the BAZ method on
FOO everywhere, i.e., with indefinite scope.  Yikes!  I want to limit
the effect of the change to the MY-FOO instance; I don't want to
affect what BAZ does with any other instance of FOO.  My way defines a
method also having indefinite scope, but that's OK because it can only
be invoked on this single FOO instance.

> Creating a closure like this is very fast and does not need to
> invoke all the machinery of creating and removing a method.  Also
> special variables are used to pass "extra" args to functions.

It's probably appropriate with functions, but I still think that with
methods one can do it more cleanly than that.
From: Wade Humeniuk
Subject: Re: Question about EQL parameter specializer
Date: 
Message-ID: <kugAd.21593$KO5.17261@clgrps13>
Aaron Gross wrote:


> When you bind *BAZ* you're changing the behavior of the BAZ method on
> FOO everywhere, i.e., with indefinite scope.  Yikes!  I want to limit
> the effect of the change to the MY-FOO instance; I don't want to
> affect what BAZ does with any other instance of FOO.  My way defines a
> method also having indefinite scope, but that's OK because it can only
> be invoked on this single FOO instance.
> 

That is not how specials work.

CL-USER 1 > (defvar *baz* 10)
*BAZ*

CL-USER 2 > (let ((*baz* 30))
               *baz*)
30

CL-USER 3 > *baz*
10

CL-USER 4 >

*baz* is a dynamic var, which means its value is bound only in
the subsequent stack frames by the let.

But if you mean that in this example,

(let* ((my-foo (make-instance 'foo ...))
        (*baz* (lambda (arg)
                 (do-some-stuff my-foo)
                 (do-something some-free-variable))))
   (declare (dynamic-extent *baz*))
   (bar my-foo)))

that bar will be calling baz multiple times with different instances
of foo, then you have to do something different.  You can do this:

(defvar *bazs* nil)

(defun baz (instance arg)
   (funcall (cdr (assoc instance *bazs*)) arg))

(let* ((my-foo (make-instance 'foo ...))
        (*bazs* *bazs*))
   (declare (dynamic-extent *bazs*))
   (push (cons my-foo (lambda (arg)
                        (do-some-stuff my-foo)
                        (do-something some-free-variable)))
         *bazs*)
   (bar my-foo))

The bar can call baz simply with (baz my-foo arg).

Wade
From: Aaron Gross
Subject: Re: Question about EQL parameter specializer
Date: 
Message-ID: <lyvfakgocw.fsf@circe.aeaea>
Wade Humeniuk <····················@telus.net> writes:

> Aaron Gross wrote:
> 
> > When you bind *BAZ* you're changing the behavior of the BAZ method
> > on FOO everywhere, i.e., with indefinite scope.  Yikes!  I want to
> > limit the effect of the change to the MY-FOO instance; I don't
> > want to affect what BAZ does with any other instance of FOO.  My
> > way defines a method also having indefinite scope, but that's OK
> > because it can only be invoked on this single FOO instance.
> 
> That is not how specials work.

I think I understand how specials work.

[...]

> *baz* is a dynamic var, which means its value is bound only in
> the subsequent stack frames by the let.

I know.  That's why I said indefinite *scope*, not indefinite extent.

> But if you mean that in this example,
> 
> (let* ((my-foo (make-instance 'foo ...))
>         (*baz* (lambda (arg)
>                  (do-some-stuff my-foo)
>                  (do-something some-free-variable))))
>    (declare (dynamic-extent *baz*))
>    (bar my-foo)))
> 
> that bar will be calling baz multiple times with different instances
> of foo, then you have to do something different.

Yes, I meant that somebody (not necessarily BAR itself) *may* possibly
be calling BAZ with different instances of FOO within the extent of
the binding, and I never ever want to rely on that *not* happening.
The reason I was horrified by your first suggestion is that you
apparently were assuming that such a thing would not happen.

> You can do this:
> 
> (defvar *bazs* nil)
> 
> (defun baz (instance arg)
>    (funcall (cdr (assoc instance *bazs*)) arg))
> 
> (let* ((my-foo (make-instance 'foo ...))
>         (*bazs* *bazs*))
>    (declare (dynamic-extent *bazs*))
>    (push (cons my-foo (lambda (arg)
>                         (do-some-stuff my-foo)
>                         (do-something some-free-variable)))
>          *bazs*)
>    (bar my-foo))
>
> The bar can call baz simply with (baz my-foo arg).

Again, you're going back and re-writing existing methods specialized
on FOO.  That would be the right thing to do when it's the right thing
to do, but it might not be the right thing to do.

But generally speaking, why invent a crude object-oriented system with
special variables, association lists, and ASSOC, when you already have
CLOS?
From: Wade Humeniuk
Subject: Re: Question about EQL parameter specializer
Date: 
Message-ID: <nxVAd.31174$KO5.29564@clgrps13>
Aaron Gross wrote:

  >
> Again, you're going back and re-writing existing methods specialized
> on FOO.  That would be the right thing to do when it's the right thing
> to do, but it might not be the right thing to do.
> 
> But generally speaking, why invent a crude object-oriented system with
> special variables, association lists, and ASSOC, when you already have
> CLOS?

Just like Kenny has asked, let's see your real code.  You wanted a hack,
so why won't my hack do? :)

Just to answer your question, because I have a affinity with crude things
and I do not think that CLOS is the answer to all things.  I fall into this
camp:

http://www.paulgraham.com/noop.html


Wade
From: John Thingstad
Subject: Re: Question about EQL parameter specializer
Date: 
Message-ID: <opsj6xttq7pqzri1@mjolner.upc.no>
On Thu, 30 Dec 2004 15:54:59 GMT, Wade Humeniuk  
<····················@telus.net> wrote:

> Aaron Gross wrote:
>
>   >
>> Again, you're going back and re-writing existing methods specialized
>> on FOO.  That would be the right thing to do when it's the right thing
>> to do, but it might not be the right thing to do.
>>  But generally speaking, why invent a crude object-oriented system with
>> special variables, association lists, and ASSOC, when you already have
>> CLOS?
>
> Just like Kenny has asked, let's see your real code.  You wanted a hack,
> so why won't my hack do? :)
>
> Just to answer your question, because I have a affinity with crude things
> and I do not think that CLOS is the answer to all things.  I fall into  
> this
> camp:
>
> http://www.paulgraham.com/noop.html
>
>
> Wade

Paul Grahams has a point.
However I think the real introduction of Object Oriented programming came  
through
introduction of windows systems.
IBM first did a survey and found that the only good way to implement
a windows system was by object orientation.
Then followed Xt (C but still object oriented), OWL (Borland) and
finally MCL (M$). So this forced programmers to learn object orientation.
Once introduced in one part of the program it tends to affect all other
parts of the program as well so ordinary code was also written in object
oriented fashion. There was a period in the early 90's when everyone
talked about object orientation but no one knew how to use it.
(I started with C++ early in 1990 and was reasonably proficient in  
C++ style OO
  by 1992)
Then came design patterns which tried to move everything into a smalltalk
style coding. This, in my opinion, is going to far.
Still since you have a one to one mapping from object to screen element in  
a
windows system OO stands out as a clear winner. (Qt is a lot better than  
MCL)
Me I moved on to Lisp and use multiple paradigms depending on the structure
of the problem.

-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
From: Wade Humeniuk
Subject: Re: Question about EQL parameter specializer
Date: 
Message-ID: <defDd.1988$06.137@clgrps12>
John Thingstad wrote:

> 
> Paul Grahams has a point.
> However I think the real introduction of Object Oriented programming 
> came  through
> introduction of windows systems.
> IBM first did a survey and found that the only good way to implement
> a windows system was by object orientation.
> Then followed Xt (C but still object oriented), OWL (Borland) and
> finally MCL (M$). So this forced programmers to learn object orientation.
> Once introduced in one part of the program it tends to affect all other
> parts of the program as well so ordinary code was also written in object
> oriented fashion. There was a period in the early 90's when everyone
> talked about object orientation but no one knew how to use it.
> (I started with C++ early in 1990 and was reasonably proficient in  C++ 
> style OO
>  by 1992)

I also started about 1990 in C++.  I think the success of OO in windowing
systems led many people to believe that it would be successful in other
areas.  It is so easy to analyze/talk about a problem in english that
it feels like it is easy to recast the problem into an OOD.  That is how
it was pitched to us in the early 1990's.  The implied assumption is that
the human mind naturally organizes things into concepts (categorizations
or objects) so a human description/solution of the problem is naturally
OO (hierarchical inheritable set of objects).  This assumes a world view
that is implicitly hierarchical and authoritative, and is amenable to
human control.  I think the sales pitch was perfectly aimed at a human
need to manage and control. This attitude directly contributes to why
many large computer projects fail, the need to control makes the system
unusable because as a central controlling solution it cannot do everything.
It overwhelms both the technical and administrative side of things.

I worked with SCADA (Supervisory Control and Data Acquisition) systems during
that time and the architecture of the system was an imitation
of the minds controlling the show.

Wade
From: Steven M. Haflich
Subject: Re: Question about EQL parameter specializer and object extent
Date: 
Message-ID: <pQ4Ad.3998$yV1.229@newssvr14.news.prodigy.com>
Aaron Gross wrote:

> On the other hand, this whole question is independent of the Lisp
> language specification, right?  Could a Lisp implementation
> automatically remove a method once it can no longer be invoked?  Or
> does that somehow violate the specification?

An implementation that includes the MOP could not automatically
remove the method, and your temporary instance would never become
garbage.  Consider the existence of the MOP functions
generic-function-methods and method-specializers.

As to the question whether your example is bad style, yes it is,
but you need look no further than the general guideline that the
CL def* forms generally are not intended to be used at execution
time.  Their behavior is defined at execution time, but that is
not how they are intended to be used and there may be performance
costs or other undesirable effects.

You should find a copy of CLtL2 online or elsewhere and read
about with-added-methods, generic-flet, and generic-labels.  These
were adopted by X3J13 as part of the original CLOS spec but
subsequently removed from the standard.  When they were originally
proposed there were no implementations and no experience how these
things might be used.  A generic function is peculiar in that it
is a single function with a distributed implementation.  Without
real experience how a programmer would manage this added dimension
of distributed implemenation, and also no real experience how these
operators would encumber the eagerly-anticipated clever efficient
implementation of generic functions, these operators were scrapped.
I thought that was the right thing to do back then, and still do.
From: Aaron Gross
Subject: Re: Question about EQL parameter specializer
Date: 
Message-ID: <lyhdm6l5yk.fsf@circe.aeaea>
"Steven M. Haflich" <·················@alum.mit.edu> writes:

> An implementation that includes the MOP could not automatically
> remove the method, and your temporary instance would never become
> garbage.  Consider the existence of the MOP functions
> generic-function-methods and method-specializers.

Actually, as I said in my follow-up to my own post, I was a little
confused at first regarding clean-up.  Clean-up would be trivial here
I think: you just bind the method objects at the beginning, evaluate
the body, and then call REMOVE-METHOD on those method objects before
exiting.

I've never learned the meta-object protocol.  Would the behavior I
just described interfere with the MOP?

> As to the question whether your example is bad style, yes it is, but
> you need look no further than the general guideline that the CL def*
> forms generally are not intended to be used at execution time.
> Their behavior is defined at execution time, but that is not how
> they are intended to be used and there may be performance costs or
> other undesirable effects.

Agreed, but what are the "other undesirable effects"?  I'd guess
unwanted bookkeeping stuff (recording the file name where the
DEFMETHOD form is located, etc.), but what else?  Speed doesn't happen
to be an issue in my case.

Regarding bookkeeping, presumably a Lisp implementation could
implement WITH-METHODS by calling whatever function DEFMETHOD calls to
do the "real work", not by calling DEFMETHOD itself.  That is, the
argument against calling DEFMETHOD at run-time is not necessarily an
argument against WITH-METHODS.

> You should find a copy of CLtL2 online or elsewhere and read
> about with-added-methods, generic-flet, and generic-labels.  These
> were adopted by X3J13 as part of the original CLOS spec but
> subsequently removed from the standard.  When they were originally
> proposed there were no implementations and no experience how these
> things might be used.  A generic function is peculiar in that it
> is a single function with a distributed implementation.  Without
> real experience how a programmer would manage this added dimension
> of distributed implemenation, and also no real experience how these
> operators would encumber the eagerly-anticipated clever efficient
> implementation of generic functions, these operators were scrapped.
> I thought that was the right thing to do back then, and still do.

Thanks for the CLtL2 cite; it was very interesting.  I agree, it looks
like it was the right decision at that time, but the reasons don't
seem relevant to the question of whether an individual programmer
should define and use a WITH-ADDED-METHODS macro, or even whether a
Lisp implementation should do so.  

More to the point, the WITH-ADDED-METHODS macro in CLtL2 seems like a
direct analogy of FLET, and therefore much milder than what I was
suggesting.  (But who really knows?  From the ANSI "delete" proposal:
"WITH-ADDED-METHODS has a strange definition that is hard to
understand and apparently is not what was intended by the person who
originally proposed the feature.")

Anyway, the difference with the CLtL2 WITH-ADDED-METHODS macro
suggests why I now think my hypothetical WITH-METHODS macro is a Bad
Idea in general.  I think it's simply a matter of scope.  My macro
temporarily defines methods with indefinite scope, so it would be way
too dangerous a tool in general.  The mitigating fact -- and it seems
crucial -- is that I wanted to specialize the method to a single
object, so that even though the method has indefinite scope, it can't
affect anything I don't want it to affect.

I *still* don't see what's so bad about this, but I do seem to have
gotten myself trapped in a corner:

1. A general WITH-METHODS macro to define methods with indefinite
   scope (as opposed to the CLtL2 WITH-ADDED-METHODS macro) would be
   dangerous.

2. It seems OK to do a WITH-METHODS sort of thing with an EQL
   parameter specifier, but 

3. it would be bad style to use DEFMETHOD to do such a thing.

So it seems that I can't do what I want without doing *something* in
bad style.  But I dislike all the other suggestions I've seen so far
on stylistic grounds as well.  I still think that perhaps my original
suggestion, defining and then removing an EQL-specialized method, is
the least bad.
From: Pascal Costanza
Subject: Re: Question about EQL parameter specializer and object extent
Date: 
Message-ID: <cqs733$828$1@newsreader2.netcologne.de>
Aaron Gross wrote:

> 3. Now, clean-up.  This seems to be the crucial point here.  Seems to
> me that the MY-FOO object will never get garbage collected, because
> it's referred to by the BAZ method -- which we want removed anyway.  I
> could just do a REMOVE-METHOD on this specialized BAZ in an
> UNWIND-PROTECT, then let the MY-FOO object get garbage collected, and
> everything would be fine -- in my *particular* case.  But that
> wouldn't work in general, because some code deep inside of
> DO-SOMETHING could, say, bind some special variable to the MY-FOO
> object (thus prolonging its extent) and then re-define BAZ specialized
> to that object -- a BAZ method that they presumably *don't* want
> removed.  So it seems out of the question to write, say, a
> WITH-METHODS macro that would remove the method at the end, because
> how would it know that it's OK to remove the method?

There's more to it. First, you have to think about what you want:

1) Do you want the new method to have lexical scope or do you want it to 
have dynamic extent ("dynamic scope")? In the former case, a local flet 
is sufficient, in the latter it's not.

(flet ((baz (arg ...)
          (if (eq arg *foo*)
              (do-something-special)
              (baz ...)))) ;; <- original baz
   ... some code ...)

2) Do you want the new method to be visible just for the current thread 
or for all threads? Many Common Lisp implementations have 
multithreading, but the default semantics for defmethod and add-method 
is to "activate" a method globally. This very likely leads to unwanted 
side effects.

In AspectL, I have implemented what I call special functions (or special 
generic functions) that allow you to define methods with dynamic extent 
which are only defined for the current thread. This requires some deep 
MOP hacking to make it work. I have solved the issue whether a method 
must be removed at the end of a definition "block" or not by separating 
the initiation of a new dynamic scope and the definition of methods for 
such a scope. So this looks roughly as follows:

(with-special-function-scope (baz)
   (defmethod* baz ((scope dynamic) ...)
     ...)

   ... some code ...)

The with-special-function-scope form acts like an unwind-protect that 
removes all the methods that have been defined for the current dynamic 
scope, no matter where they have been defined. I think that's reasonable 
and solves some of the issues that with-added-method had in CLtL2.

[defmethod* must be used instead of defmethod for some internal reasons, 
mainly to circumvent MOP incompatibilities. I hope to be able to make 
this simpler in the near future.]


Pascal

-- 
The big bang way only works for god, everybody else has to use 
evolution. - David Moon
From: Jim Newton
Subject: method qualifiers
Date: 
Message-ID: <33dmqfF3v9pfdU1@individual.net>
hi pascal, o master of the mop.

remember the question we discussed recently about having
more than one method qualifier on a given method.  Well
i have noticed that all of the explanations in the AOTMP
they always test method qualifier lists for equality
rather than membership.

(defun around-method-p (method)
   (equal '(:around) (method-qualifiers method)))

I'm always tempted to reimplement this in my own
implementation for SKILL to be something like the following
(with SKILL syntax, hope it is ok)

(defmethod ClosAroundMethodP (( method ClosStdMethod))
    (member 'around (ClosMethodAualifiers method)))

It makes more sense to me but doing so will make it
perhaps more difficult for a new user to use because it does
not follow the specification.

Perhaps better is

(defmethod ClosAroundMethodP (( method ClosStdMethod))
    (equal'(around) (ClosMethodAualifiers method)))

but allowing ClosAroundMethodP to be overridden in
subclasses of ClosStdMethod.

What do you think?

-jim
From: Pascal Costanza
Subject: Re: method qualifiers
Date: 
Message-ID: <cqs9bi$c39$1@newsreader2.netcologne.de>
Jim Newton wrote:
> hi pascal, o master of the mop.

oh dear... ;)

> remember the question we discussed recently about having
> more than one method qualifier on a given method.  Well
> i have noticed that all of the explanations in the AOTMP
> they always test method qualifier lists for equality
> rather than membership.
> 
> (defun around-method-p (method)
>   (equal '(:around) (method-qualifiers method)))
> 
> I'm always tempted to reimplement this in my own
> implementation for SKILL to be something like the following
> (with SKILL syntax, hope it is ok)
> 
> (defmethod ClosAroundMethodP (( method ClosStdMethod))
>    (member 'around (ClosMethodAualifiers method)))
> 
> It makes more sense to me but doing so will make it
> perhaps more difficult for a new user to use because it does
> not follow the specification.
> 
> Perhaps better is
> 
> (defmethod ClosAroundMethodP (( method ClosStdMethod))
>    (equal'(around) (ClosMethodAualifiers method)))
> 
> but allowing ClosAroundMethodP to be overridden in
> subclasses of ClosStdMethod.
> 
> What do you think?

I think the latter is ok. I think it's very unlikely that arbitrary 
qualifiers can be combined without them "knowing" about each other, so a 
membership test probably doesn't give you anything for free.

For example, someone could want to have several around "layers" sorted 
by a second integer qualifier, like this:

(defmethod bla :around 1 (...)
   ...)

(defmethod bla :around 2 (...)
   ...)

This is already a simple example where the membership test doesn't tell 
you how to combine a method with the other ones.


Pascal

-- 
The big bang way only works for god, everybody else has to use 
evolution. - David Moon
From: Aaron Gross
Subject: Re: with-added-methods and with-special-function-scope
Date: 
Message-ID: <lymzvwgo5d.fsf@circe.aeaea>
Before posting this message, I read another post that convinced me
that my original idea was a Bad Idea.  But I'm still posting this
because CLtL2's WITH-ADDED-METHODS macro and the
WITH-SPECIAL-FUNCTION-SCOPE macro that Pascal described are
interesting.

Pascal Costanza <········@web.de> writes:

> 1) Do you want the new method to have lexical scope or do you want it to 
> have dynamic extent ("dynamic scope")?  In the former case, a local
> flet is sufficient, in the latter it's not.

I want the latter case: dynamic extent and indefinite scope (but see
below about threads).

> 2) Do you want the new method to be visible just for the current thread 
> or for all threads? Many Common Lisp implementations have
> multithreading, but the default semantics for defmethod and
> add-method is to "activate" a method globally. This very likely
> leads to unwanted side effects.

I hadn't thought about multi-threading at all.  I think I just want the
current thread.  I'd have to think about it a lot more to be halfway
certain, though.

> In AspectL, I have implemented what I call special functions (or special 
> generic functions) that allow you to define methods with dynamic extent 
> which are only defined for the current thread. This requires some deep 
> MOP hacking to make it work. I have solved the issue whether a method 
> must be removed at the end of a definition "block" or not by separating 
> the initiation of a new dynamic scope and the definition of methods for 
> such a scope. 

I don't see the problem you were trying to solve there.  Assuming a
WITH-ADDED-METHODS kind of syntax, and not the syntax of your
WITH-SPECIAL-FUNCTION-SCOPE that you define below, I'd think that the
method *object* should always be removed before exiting the form,
shouldn't it?  I thought that if somebody redefines that method during
the body, then that new definition will replace the old method with a
*new* method object, which will stay.  What am I missing here?

I do see a clean-up problem with generic functions, not methods.  (I'm
still talking about a WITH-ADDED-METHODS-style syntax, not your
WITH-SPECIAL-FUNCTION-SCOPE.)  If one of the dynamically scoped
methods ensures the existence of a brand new generic function, then
you'd na�vely "want" to FMAKUNBOUND the generic function at clean-up.
But what if, during execution of the macro body, some
ENSURE-GENERIC-FUNCTION form ensured the existence of that same
generic function?  In that case you shouldn't unbind it at clean-up.
Hence the MOP has to keep tabs on what's going on.  Am I sort of on
the right track?  But I still don't see how that relates to removing
methods.

Any elaboration you may want to provide would be appreciated,
especially if you could explain at a low enough level that I could
understand (not knowing the MOP).  In any case, I see now that a
WITH-ADDED-METHODS macro is a lot more complicated than what I'd
na�vely imagined.

> So this looks roughly as follows:
>
> (with-special-function-scope (baz)
>    (defmethod* baz ((scope dynamic) ...)
>      ...)
> 
>    ... some code ...)
>
> The with-special-function-scope form acts like an unwind-protect that 
> removes all the methods that have been defined for the current dynamic 
> scope, no matter where they have been defined. I think that's reasonable 
> and solves some of the issues that with-added-method had in CLtL2.
>
> [defmethod* must be used instead of defmethod for some internal
> reasons, mainly to circumvent MOP incompatibilities. I hope to be
> able to make this simpler in the near future.]

Someone objected to my use of DEFMETHOD, on the grounds that calling a
DEF* form at run time is bad style.  That sounded like a valid
objection to me.  What do you think about it, in relation to your
DEFMETHOD* as opposed to DEFMETHOD?

Another question.  What are those issues that WITH-ADDED-METHODS had
in CLtL2?  (Presumably one of them is the problem removing methods you
alluded to above.)  My impression was that WITH-ADDED-METHODS was an
analogue of FLET for methods -- that is, lexical scope -- though
apparently there was some confusion about what exactly it was supposed
to do.  I'd be interested in any history that you or anyone else might
want to share.
From: Pascal Costanza
Subject: Re: with-added-methods and with-special-function-scope
Date: 
Message-ID: <cr0mp7$5d7$1@newsreader2.netcologne.de>
Aaron Gross wrote:

>>In AspectL, I have implemented what I call special functions (or special 
>>generic functions) that allow you to define methods with dynamic extent 
>>which are only defined for the current thread. This requires some deep 
>>MOP hacking to make it work. I have solved the issue whether a method 
>>must be removed at the end of a definition "block" or not by separating 
>>the initiation of a new dynamic scope and the definition of methods for 
>>such a scope. 
> 
> I don't see the problem you were trying to solve there.  Assuming a
> WITH-ADDED-METHODS kind of syntax, and not the syntax of your
> WITH-SPECIAL-FUNCTION-SCOPE that you define below, I'd think that the
> method *object* should always be removed before exiting the form,
> shouldn't it?  I thought that if somebody redefines that method during
> the body, then that new definition will replace the old method with a
> *new* method object, which will stay.  What am I missing here?

The metaobject protocol is there to implement the semantics that you 
want. One shouldn't let the semantics be driven by what the MOP suggests 
on a superficial level. In other words, I don't think it makes a lot of 
sense to think about the method objects at the "user" level. What's more 
important is the question what we want from a WITH-ADDED-METHODS / 
WITH-SPECIAL-FUNCTION-SCOPE construct.

If you use DEFMETHOD (or use some other means to define a method at 
runtime) I have imagined that there are two useful cases: Either you 
want it to be globally defined or you want it to be defined for the 
current dynamic scope. In AspectL you can say either (DEFMETHOD ... 
((SCOPE T) ...) ...) or (DEFMETHOD ... ((SCOPE DYNAMIC) ...) ...). The 
first form defines a method globally, the second one for the current 
dynamic scope. On exit from a WITH-SPECIAL-FUNCTON-SCOPE block all the 
methods that are defined for that dynamic scope are removed because they 
cannot be called anymore anyway. I think this is a natural thing to do 
here, and it popped out from separating scope and method definition.

(Originally I have used the WITH-SPECIAL-FUNCTION-SCOPE approach because 
WITH-ADDED-METHODS would be much harder to parse and especially to check 
for correctness, because one would have to check for methods with the 
same qualifiers and specializers in the same WITH-ADDED-METHODS form. I 
don't have to do that in WITH-SPECIAL-FUNCTION-SCOPE. I am just lazy. ;)

> I do see a clean-up problem with generic functions, not methods.  (I'm
> still talking about a WITH-ADDED-METHODS-style syntax, not your
> WITH-SPECIAL-FUNCTION-SCOPE.)  If one of the dynamically scoped
> methods ensures the existence of a brand new generic function, then
> you'd na�vely "want" to FMAKUNBOUND the generic function at clean-up.
> But what if, during execution of the macro body, some
> ENSURE-GENERIC-FUNCTION form ensured the existence of that same
> generic function?  In that case you shouldn't unbind it at clean-up.
> Hence the MOP has to keep tabs on what's going on.  Am I sort of on
> the right track?  But I still don't see how that relates to removing
> methods.

Hm, I have no good idea how to solve that either. But in AspectL this 
doesn't come up because one has to globally declare a function to be 
special anyway before one can use WITH-SPECIAL-FUNCTION-SCOPE, so 
ENSURE-GENERIC-FUNCTION wouldn't have any interesting effect.

> Any elaboration you may want to provide would be appreciated,
> especially if you could explain at a low enough level that I could
> understand (not knowing the MOP).  In any case, I see now that a
> WITH-ADDED-METHODS macro is a lot more complicated than what I'd
> na�vely imagined.

Yep. I hope my explanations above are clearer than before.

> Someone objected to my use of DEFMETHOD, on the grounds that calling a
> DEF* form at run time is bad style.  That sounded like a valid
> objection to me.  What do you think about it, in relation to your
> DEFMETHOD* as opposed to DEFMETHOD?

DEFMETHOD* is a hack. I would really prefer to be able to use DEFMETHOD 
everywhere, and I hope to be able to achieve that in a future version of 
AspectL.

I don't think that using DEFMETHOD at runtime is bad style. I don't know 
what more to say about this. Style is a matter of taste, isn't it? ;)

> Another question.  What are those issues that WITH-ADDED-METHODS had
> in CLtL2?  (Presumably one of them is the problem removing methods you
> alluded to above.)  My impression was that WITH-ADDED-METHODS was an
> analogue of FLET for methods -- that is, lexical scope -- though
> apparently there was some confusion about what exactly it was supposed
> to do.  I'd be interested in any history that you or anyone else might
> want to share.

Check out the HyperSpec, it has a rationale why this was rejected (in 
the issues listing). There is also some discussion about 
WITH-ADDED-METHODS and GENERIC-FLET in the CLOS/MOP mailing list 
archive. However, this was when they wanted it in.

It seems to me that the original idea was to have dynamic scoping for 
the added methods, but the CLOS designers have never been explicit in 
that regard. When these constructs entered the CLOS specification, they 
assumed lexical scoping at some stage. This is probably because lexical 
scoping was still "hot" at that time. ;)

The main reasons why these constructs were rejected, as far as I recall 
them, were a) existing CLOS implementations would have needed drastic 
changes in order to make them work, b) the semantics were not 100% clear 
and c) there was no prior art in using such features, so it was doubtful 
whether they would make sense.

I really think that lexically scoped GENERIC-FLET and/or 
WITH-ADDED-METHODS are useless.


Pascal

-- 
The big bang way only works for god, everybody else has to use 
evolution. - David Moon
From: Aaron Gross
Subject: Re: with-added-methods and with-special-function-scope
Date: 
Message-ID: <ly3bxnhnrt.fsf@circe.aeaea>
Pascal Costanza <········@web.de> writes:

> The metaobject protocol is there to implement the semantics that you
> want. One shouldn't let the semantics be driven by what the MOP
> suggests on a superficial level. In other words, I don't think it
> makes a lot of sense to think about the method objects at the "user"
> level. What's more important is the question what we want from a
> WITH-ADDED-METHODS / WITH-SPECIAL-FUNCTION-SCOPE construct.

Yes, I see that now.  I had been thinking that a WITH-ADDED-METHODS
removing method objects in the clean-up form was basically like a
WITH-OPEN-FILE closing the stream object, but I see that's a bad
analogy.  That would have been immediately obvious to me if I had
known what meta-objects *are* (I know now), even without knowing
anything else about the MOP.

> If you use DEFMETHOD (or use some other means to define a method at 
> runtime) I have imagined that there are two useful cases: Either you 
> want it to be globally defined or you want it to be defined for the 
> current dynamic scope. In AspectL you can say either (DEFMETHOD ... 
> ((SCOPE T) ...) ...) or (DEFMETHOD ... ((SCOPE DYNAMIC) ...) ...). The 
> first form defines a method globally, the second one for the current 
> dynamic scope. On exit from a WITH-SPECIAL-FUNCTON-SCOPE block all the 
> methods that are defined for that dynamic scope are removed because they 
> cannot be called anymore anyway. I think this is a natural thing to do 
> here, and it popped out from separating scope and method definition.

So does "current" dynamic scope mean that in

(with-special-function-scope (baz)
  (with-special-function-scope (bar)
    (defmethod* baz ((scope dynamic) ...)
      ...)
    ... some code ...)
  ...some more code...)

the BAZ method will extend until exit from the outer form, so that
"some more code" could call that BAZ method?  If so, why would someone
want to do that?  If not, then the (BAZ) argument to
WITH-SPECIAL-FUNCTION-SCOPE seems redundant, given the (SCOPE DYNAMIC)
declaration.

> (Originally I have used the WITH-SPECIAL-FUNCTION-SCOPE approach
> because WITH-ADDED-METHODS would be much harder to parse and
> especially to check for correctness, because one would have to check
> for methods with the same qualifiers and specializers in the same
> WITH-ADDED-METHODS form. I don't have to do that in
> WITH-SPECIAL-FUNCTION-SCOPE. I am just lazy. ;)

Laziness is always good, but concerning the ideal syntax, I really
think the WITH-ADDED-METHODS syntax would be much better for any such
macro.  (I'm not suggesting that anyone take my advice on style, given
what started this whole thread.)  For one thing, it's like the
existing FLET, LABELS, etc.  Seems like a Good Thing to separate the
definitions from the body, for various reasons.

> I really think that lexically scoped GENERIC-FLET and/or
> WITH-ADDED-METHODS are useless.

Yep, that was my first thought too when I read the CLtL2 definition of
WITH-ADDED-METHODS (lexically scoped) yesterday: What good would
*that* do?  Now it makes sense, if as you suggest the original idea
was to have dynamic scoping.
From: Pascal Costanza
Subject: Re: with-added-methods and with-special-function-scope
Date: 
Message-ID: <cr17d1$4os$1@newsreader2.netcologne.de>
Aaron Gross wrote:

> So does "current" dynamic scope mean that in
> 
> (with-special-function-scope (baz)
>   (with-special-function-scope (bar)
>     (defmethod* baz ((scope dynamic) ...)
>       ...)
>     ... some code ...)
>   ...some more code...)
> 
> the BAZ method will extend until exit from the outer form, so that
> "some more code" could call that BAZ method?  If so, why would someone
> want to do that?

I don't know, but keep in mind that BAZ and BAR may be unrelated and 
their respective dynamic scopes may be set up in different code pieces, 
for example:

(with-special-function-scope (baz)
   (with-some-other-macro
     (defmethod* baz ((scope dynamic) ...)
       ...)
     ... some code ...)
   ... some more code ...)

...now with-some-other-macro may or may not expand to a special function 
scope for bar, but the meaning of the rest of the code shouldn't change 
its meaning just because of that.


>>(Originally I have used the WITH-SPECIAL-FUNCTION-SCOPE approach
>>because WITH-ADDED-METHODS would be much harder to parse and
>>especially to check for correctness, because one would have to check
>>for methods with the same qualifiers and specializers in the same
>>WITH-ADDED-METHODS form. I don't have to do that in
>>WITH-SPECIAL-FUNCTION-SCOPE. I am just lazy. ;)
> 
> Laziness is always good, but concerning the ideal syntax, I really
> think the WITH-ADDED-METHODS syntax would be much better for any such
> macro.  (I'm not suggesting that anyone take my advice on style, given
> what started this whole thread.)  For one thing, it's like the
> existing FLET, LABELS, etc.  Seems like a Good Thing to separate the
> definitions from the body, for various reasons.

One main reason I would like to keep things as they are is that I don't 
know what to do with method definitions in a WITH-ADDED-METHODS form 
that don't have a corresponding special function definition somewhere 
else. I'd like to avoid having to define some arbitrary defaults here 
that might surprise people.

Another issue is this:

(with-added-method
     ((m ((arg some-type))
        ...)
      (m ((arg some-type))
        ...))
   ...)

What's the meaning of that code? (The important thing here is that both 
Ms have the same specializers.

(Related question: Do we need WITH-ADDED-METHOD* ?)



Pascal

-- 
The big bang way only works for god, everybody else has to use 
evolution. - David Moon
From: Aaron Gross
Subject: Re: with-added-methods and with-special-function-scope
Date: 
Message-ID: <lyllbcdpee.fsf@circe.aeaea>
Pascal Costanza <········@web.de> writes:

> Aaron Gross wrote:
> 
> > So does "current" dynamic scope mean that in
> > 
> > (with-special-function-scope (baz)
> >   (with-special-function-scope (bar)
> >     (defmethod* baz ((scope dynamic) ...)
> >       ...)
> >     ... some code ...)
> >   ...some more code...)
> > 
> > the BAZ method will extend until exit from the outer form, so that
> > "some more code" could call that BAZ method?  If so, why would someone
> > want to do that?
> 
> I don't know, but keep in mind that BAZ and BAR may be unrelated and 
> their respective dynamic scopes may be set up in different code pieces, 
> for example:
> 
> (with-special-function-scope (baz)
>    (with-some-other-macro
>      (defmethod* baz ((scope dynamic) ...)
>        ...)
>      ... some code ...)
>    ... some more code ...)
> 
> ...now with-some-other-macro may or may not expand to a special function 
> scope for bar, but the meaning of the rest of the code shouldn't change 
> its meaning just because of that.

This looks like a serious problem that was caused by your solution of
separating "scope initiation" and method definition, which in turn was
a result of your requiring explicit special function definitions,
which in turn was a result of...?  Now you're stuck with unfriendly
syntax, where the programmer has to specify the scope explicitly for
each method (careful, don't forget one!).  You know your code and I
don't, but it looks like removing that explicit function definition
requirement, painful as it may be, might possibly make everything else
much simpler (including the syntax).

> > Laziness is always good, but concerning the ideal syntax, I really
> > think the WITH-ADDED-METHODS syntax would be much better for any
> > such macro.  (I'm not suggesting that anyone take my advice on
> > style, given what started this whole thread.)  For one thing, it's
> > like the existing FLET, LABELS, etc.  Seems like a Good Thing to
> > separate the definitions from the body, for various reasons.

I forgot to ask, regarding laziness and parsing the method definition
forms -- isn't that work already done for you somewhere as part of the
DEFMETHOD implementation?  Seems like it would just be a matter of
calling some low-level parser function that DEFMETHOD already calls.

> One main reason I would like to keep things as they are is that I
> don't know what to do with method definitions in a
> WITH-ADDED-METHODS form that don't have a corresponding special
> function definition somewhere else. I'd like to avoid having to
> define some arbitrary defaults here that might surprise people.

Maybe just change the name to WITH-ADDED-DYNAMIC-METHODS?  Or if we
agree that a lexically scoped WITH-ADDED-METHODS macro is pretty
useless, why not just specify that all the methods defined by the
macro (not in the body) have dynamic scope?  That doesn't sound
arbitrary to me.  Then your method definition in the (dynamically
scoping) WITH-ADDED-METHODS would have the same semantics as your
DEFMETHOD((SCOPE DYNAMIC) ...)  form inside a
WITH-SPECIAL-FUNCTION-SCOPE.  Aside from the horror of having to
write, or look up, a little bit of parser code, what's the big deal?

> Another issue is this:
> 
> (with-added-method
>      ((m ((arg some-type))
>         ...)
>       (m ((arg some-type))
>         ...))
>    ...)
> 
> What's the meaning of that code? (The important thing here is that both 
> Ms have the same specializers.

Is that such a big deal?  You decide what the meaning will be -- maybe
similar to FLET, or an error, or whatever -- and specify it.

> (Related question: Do we need WITH-ADDED-METHOD* ?)

Do we need FLET*?
From: Pascal Costanza
Subject: Re: with-added-methods and with-special-function-scope
Date: 
Message-ID: <cs3o3j$o6c$1@snic.vub.ac.be>
Aaron Gross wrote:
> Pascal Costanza <········@web.de> writes:
> 
>>Aaron Gross wrote:
>>
>>>So does "current" dynamic scope mean that in
>>>
>>>(with-special-function-scope (baz)
>>>  (with-special-function-scope (bar)
>>>    (defmethod* baz ((scope dynamic) ...)
>>>      ...)
>>>    ... some code ...)
>>>  ...some more code...)
>>>
>>>the BAZ method will extend until exit from the outer form, so that
>>>"some more code" could call that BAZ method?  If so, why would someone
>>>want to do that?
>>
>>I don't know, but keep in mind that BAZ and BAR may be unrelated and 
>>their respective dynamic scopes may be set up in different code pieces, 
>>for example:
>>
>>(with-special-function-scope (baz)
>>   (with-some-other-macro
>>     (defmethod* baz ((scope dynamic) ...)
>>       ...)
>>     ... some code ...)
>>   ... some more code ...)
>>
>>...now with-some-other-macro may or may not expand to a special function 
>>scope for bar, but the meaning of the rest of the code shouldn't change 
>>its meaning just because of that.
> 
> This looks like a serious problem that was caused by your solution of
> separating "scope initiation" and method definition, which in turn was
> a result of your requiring explicit special function definitions,
> which in turn was a result of...?

In what respect would that be "serious"?

> Now you're stuck with unfriendly
> syntax, where the programmer has to specify the scope explicitly for
> each method (careful, don't forget one!).  You know your code and I
> don't, but it looks like removing that explicit function definition
> requirement, painful as it may be, might possibly make everything else
> much simpler (including the syntax).

No, not really.

> I forgot to ask, regarding laziness and parsing the method definition
> forms -- isn't that work already done for you somewhere as part of the
> DEFMETHOD implementation?  Seems like it would just be a matter of
> calling some low-level parser function that DEFMETHOD already calls.

No. It wouldn't help detecting conflicts either.

>>One main reason I would like to keep things as they are is that I
>>don't know what to do with method definitions in a
>>WITH-ADDED-METHODS form that don't have a corresponding special
>>function definition somewhere else. I'd like to avoid having to
>>define some arbitrary defaults here that might surprise people.
> 
> Maybe just change the name to WITH-ADDED-DYNAMIC-METHODS?  Or if we
> agree that a lexically scoped WITH-ADDED-METHODS macro is pretty
> useless, why not just specify that all the methods defined by the
> macro (not in the body) have dynamic scope?  That doesn't sound
> arbitrary to me.

I think some Common Lisps have implemented WITH-ADDED-METHODS.

> Then your method definition in the (dynamically
> scoping) WITH-ADDED-METHODS would have the same semantics as your
> DEFMETHOD((SCOPE DYNAMIC) ...)  form inside a
> WITH-SPECIAL-FUNCTION-SCOPE.  Aside from the horror of having to
> write, or look up, a little bit of parser code, what's the big deal?

As I explained earlier on, you have to find a semantics for methods that 
are added/changed/removed in the dynamic extent of a 
WITH-(DYNAMICALLY-)ADDED-METHODS form. Are they removed at the end of 
such a form as well, do they stay afterwards, and if so, why?

The advantage of my approach is that the semantics are very simple. It 
requires the programmer to type more, but it's always clear what's 
happening. In your suggested approach, I would have to define some 
aribtrary semantics that a programmer either has to memorize or look up, 
not to mention potentially surprising behavior.

Of course, I would welcome a good rationale for what you propose.

>>Another issue is this:
>>
>>(with-added-method
>>     ((m ((arg some-type))
>>        ...)
>>      (m ((arg some-type))
>>        ...))
>>   ...)
>>
>>What's the meaning of that code? (The important thing here is that both 
>>Ms have the same specializers.
> 
> Is that such a big deal?  You decide what the meaning will be -- maybe
> similar to FLET, or an error, or whatever -- and specify it.

What do you suggest?



Pascal
From: Aaron Gross
Subject: Re: with-added-methods and with-special-function-scope
Date: 
Message-ID: <lyoeg8dpfb.fsf@circe.aeaea>
Aaron Gross <·······@bloomberg.com.invalid> writes:

> Pascal Costanza <········@web.de> writes:
> 
> > The metaobject protocol is there to implement the semantics that
> > you want. One shouldn't let the semantics be driven by what the
> > MOP suggests on a superficial level. In other words, I don't think
> > it makes a lot of sense to think about the method objects at the
> > "user" level. What's more important is the question what we want
> > from a WITH-ADDED-METHODS / WITH-SPECIAL-FUNCTION-SCOPE construct.
> 
> Yes, I see that now.  I had been thinking that a WITH-ADDED-METHODS
> removing method objects in the clean-up form was basically like a
> WITH-OPEN-FILE closing the stream object, but I see that's a bad
> analogy.  That would have been immediately obvious to me if I had
> known what meta-objects *are* (I know now), even without knowing
> anything else about the MOP.

Actually, now that I've glanced through _The Art of the Metaobject
Protocol_, the WITH-OPEN-FILE analogy doesn't seem so bad.  I see
WITH-ADDED-METHODS as creating new method objects with some
MAKE-PROGRAMMATIC-METHOD function -- if it's not already in the MOP,
then implemented via the MOP -- and binding those objects in a LET.
Then in the UNWIND-PROTECT clean-up form, the macro calls
REMOVE-METHOD on the new method objects.  According to AMOP, "The
generic function REMOVE-METHOD can be called by the user or the
implementation".

So WITH-ADDED-METHODS is a user macro implemented using the MOP;
you're already using the MOP to create the methods, unless you want to
call DEFMETHOD which (I agree with Steven) is bad style.  Of course
method objects are transparent to the user of WITH-ADDED-METHODS, just
as they're transparent to a user of, say, a class browser implemented
with the MOP.  At first I'd thought (above) that REMOVE-METHOD was
some low-level function that you shouldn't use directly, but that
doesn't seem to be the case.  So I still don't see what's wrong with
calling REMOVE-METHOD explicitly in clean-up.  And since, as I've said
elsewhere, I don't especially like that idea of having some explicit
"scope delimiter", this would seem to be the most natural way to
remove the methods at the right time.
From: Pascal Costanza
Subject: Re: with-added-methods and with-special-function-scope
Date: 
Message-ID: <cs3opi$p32$1@snic.vub.ac.be>
Aaron Gross wrote:
> Aaron Gross <·······@bloomberg.com.invalid> writes:
> 
>>Pascal Costanza <········@web.de> writes:
>>
>>>The metaobject protocol is there to implement the semantics that
>>>you want. One shouldn't let the semantics be driven by what the
>>>MOP suggests on a superficial level. In other words, I don't think
>>>it makes a lot of sense to think about the method objects at the
>>>"user" level. What's more important is the question what we want
>>>from a WITH-ADDED-METHODS / WITH-SPECIAL-FUNCTION-SCOPE construct.
>>
>>Yes, I see that now.  I had been thinking that a WITH-ADDED-METHODS
>>removing method objects in the clean-up form was basically like a
>>WITH-OPEN-FILE closing the stream object, but I see that's a bad
>>analogy.  That would have been immediately obvious to me if I had
>>known what meta-objects *are* (I know now), even without knowing
>>anything else about the MOP.
> 
> Actually, now that I've glanced through _The Art of the Metaobject
> Protocol_, the WITH-OPEN-FILE analogy doesn't seem so bad.  I see
> WITH-ADDED-METHODS as creating new method objects with some
> MAKE-PROGRAMMATIC-METHOD function -- if it's not already in the MOP,
> then implemented via the MOP -- and binding those objects in a LET.
> Then in the UNWIND-PROTECT clean-up form, the macro calls
> REMOVE-METHOD on the new method objects.  According to AMOP, "The
> generic function REMOVE-METHOD can be called by the user or the
> implementation".
> 
> So WITH-ADDED-METHODS is a user macro implemented using the MOP;
> you're already using the MOP to create the methods, unless you want to
> call DEFMETHOD which (I agree with Steven) is bad style.  Of course
> method objects are transparent to the user of WITH-ADDED-METHODS, just
> as they're transparent to a user of, say, a class browser implemented
> with the MOP.  At first I'd thought (above) that REMOVE-METHOD was
> some low-level function that you shouldn't use directly, but that
> doesn't seem to be the case.  So I still don't see what's wrong with
> calling REMOVE-METHOD explicitly in clean-up.  And since, as I've said
> elsewhere, I don't especially like that idea of having some explicit
> "scope delimiter", this would seem to be the most natural way to
> remove the methods at the right time.

What's the result of the following code snippet?

(progn
   (defmethod m (x)
     (print x))

   (with-added-methods
     ((m ((x integer))
        (call-next-method (1+ x))))

     (defmethod m ((x integer))
       (call-next-method (+ x x))))

   (m 5))


Is it 5, 6, 10 or an exception? Why? (Note that DEFMETHOD has 
well-defined semantics here. It doesn't matter whether you think it's 
bad style or not.)

Compare this with the following two examples:

(progn
   (defmethod m ((scope t) x)
     (print x))

   (with-special-function-scope (m)
     (defmethod m ((scope dynamic) (x integer))
       (call-next-method (1+ x)))

     (defmethod m ((scope dynamic) (x integer))
       (call-next-method (+ x x))))

   (m 5))

(progn
   (defmethod m ((scope t) x)
     (print x))

   (with-special-function-scope (m)
     (defmethod m ((scope dynamic) (x integer))
       (call-next-method (1+ x)))

     (defmethod m ((scope t) (x integer))
       (call-next-method (+ x x))))

   (m 5))


I think it's much clearer what is going to happen in the latter two cases.


Pascal
From: Aaron Gross
Subject: Re: with-added-methods and with-special-function-scope
Date: 
Message-ID: <lyr7l4dpg2.fsf@circe.aeaea>
Pascal Costanza <········@web.de> writes:

> Aaron Gross wrote:
> 
> > Someone objected to my use of DEFMETHOD, on the grounds that
> > calling a DEF* form at run time is bad style.  That sounded like a
> > valid objection to me.  What do you think about it, in relation to
> > your DEFMETHOD* as opposed to DEFMETHOD?

[...]

> I don't think that using DEFMETHOD at runtime is bad style. I don't
> know what more to say about this. Style is a matter of taste, isn't
> it? ;)

In the last few days I've just started looking into _The Art of the
Metaobject Protocol_, and in Section 2.4, "Programmatic Creation of
New Classes", they talk about creating instances, anonymous classes,
generic functions, and methods at run-time with
MAKE-PROGRAMMATIC-INSTANCE, MAKE-PROGRAMMATIC-CLASS, and friends:

    Although it would be possible to write explicit class definitions
    for all valid combinations, it would be tedious to do so -- and
    wasteful if only a few of the combinations are actually
    instantiated in any single execution of the graphics application.
    In such cases it would be desirable to hold off defining the
    combination classes and creating the corresponding class
    metaobjects until that combination is actually needed.  So, for
    example, to create an instance of the class of orange circles
    labeled at the top, we would call some function
    MAKE-PROGRAMMATIC-INSTANCE giving the names of the appropriate
    superclasses along with the initialization arguments for the
    instance...

    . . .

    Programmatic creation of generic function and method metaobjects
    is supported by analogous metaobject protocols for invoking
    MAKE-INSTANCE; the details of the protocols are not included
    here. 

As I said elsewhere, I'm convinced now that "programmatically"
creating a method was the wrong thing to do in my example (and
programmatically creating a class would have been wrong for the same
reason).  But I still think it could be the right thing to do in some
applications.  Seems to me, if you want to create methods with dynamic
extent, then this would be the way to go.