Method wrapping

This sound all good and well however this does not change the
fact that you CANNOT use "old hook methods’’ if the signature
(arity) of the primary method changed - in this case you have
to trash the current hook method stack in one way or the other.

If the arity goes up, you can avoid problems provided the first arguments
remain the same and your hook doesn’t care about them by using a *arg as
in my example…

I feel you gave only very weak argument why in this particular
circumstance the removal shouldn’t happen automatically.

OK, I didn’t realize your argument was in case of arity changes, just like
you didn’t realize my argument was for the general case. Cool! But
seriously, if that particular circumstance is rare enough, why care?
(Gee, they already brainwashed me :slight_smile: So you still need to show that a
change in arity happens often enough compared to say change of
implementation. I think that highly depends on how you write your code,
whether you work top-down - first get the interfaces right, then implement

  • or bottom-up - start implementing small parts and build on that to make
    larger parts. Or whether you combine both.

Also, if you’d change a method and need extra arguments for extra
functionality, then if your hook can’t handle those extra arguments
generically, that’s pretty tight coupling, isn’t it?

Peter

Actually I have rethought this. Wrappers do depend on the implementation b/c
their proper functionality depends on what is returned, not just what
kind. They may not raise an error if the kinds are the same, but that
doesn’t mean they work right. So my original wording was more correct.

-t0

···

On Thursday 27 November 2003 08:57 am, T. Onoma wrote:

Wrappers don’t depend on the implementation of a method, as you
assert. They depend on the interface. The wrappers should have no
real side-effect anyway, I suspect, except for logging, asserting, …

Of course, I was referreing to the interface of the implementation. Sorry,
for not being more specific.

I can understand where you’re coming from with this. You want the
functionality there just in case for those “some cases”. But by and large you
won’t want this behiavor (for many reasons), so it really should not be the
default. On the rare occassions one does want it, then there can be means
available to replace the method chain’s “heart” or even any particluar wrap
layer. But doing so should have its own special method, not the other way
around. Otherwise we’re going to end up with a lot of code heavily littered
with:

remove_method(:ameth)
def ameth
end

What are wrappers going to be used for? Are you only supposed to add
wrappers to your own code? How about keeping some statistics about calls
to some library? I could write a proxy object that does that for me, but
wrappers are more flexible I guess. If I do that, some methods may have my
wrappers wrapped around them, or some of the library’s, or some other
library’s. That sounds plausible, doesn’t it? Then if the wrappers are
removed on redefinition of a method, arranging the wrappers to be
reinstalled is a tough job, and it might not even be necessary if your
wrappers are defined well and the method changes are not at random.
Increasing arity can be caught with a *args in the argument list. I use
that in my initialize methods to call the initialize method in the
superclass. As such, I can add arguments to the initialize method of the
superclass and subclasses can beautifully pass them on without caring how
many there really are.

So my point is then that rarely wrappers would need to be reinstalled if
care is taken. If they do need reinstalling, the code for that isn’t
always obvious and I don’t need my code to be littered with weird,
unnecessary code.

That’s certainly not the Ruby Way. I’m not sure what kind of method to use for
your case though, perhaps like

selective_def(index, :ameth, *args) do
end

To replace the “heart” you’d use index=0. Hey! Better yet, perhaps we can have
some array like sugar:

def ameth0
end

I think that would work nicely. You?

Like I said, wrappers can get mixed and I don’t want to count on a certain
wrapper being in a certain position in the stack. If wrappers can be
added/removed, e.g., for turning logging on/off, positions change. Keeping
track of those positions is not my idea of good separation of concerns. I
like (optional) identifiers for wrappers better, but that’s apparently
just me…

But again, what will be the use of those wrappers? A lot of it will depend
on that. If it’s supposed to be used for modeling cross-cutting concerns
like in AOP, reinstalling wrappers could prove to be awkward.

Maybe I’m just thinking too much about all this…

Peter

If you are redefining someone else’s method in production, on your own
head be it. You should be keeping to the same interface of the
original, or else other code is likely to break.

Exactly, and to do this requires understanding the interface. And more
times than not, if you are REDEFINING a method in this manner, your doing
it in totality. Juggling the hooks from before is not condusive. You’ll
end up remove_method’ing them all anyway.

OK, I’ll add my take from the perspective of someone that’s not played
with Ruby that long.

My first reaction to all this wrapper talk was ‘WTF?’, because it
seemed very odd to me. But I think I’ve gotten the idea now.

It is rather odd. Aspect Oriented Programming is still rather new and I thnk
has a lot of utepped potential yet.

As I see it, wrapping is for those ‘I want this too’ situations, you
don’t really want to change the original method, but you need a bit of
extra code. Debugging statements and logging of use springs to
mind. The important part being that the extra code doesn’t muck with
the interface.

Let me give you an example of what you can do with AOP. I wrote a Ruby script
that took an object and wrapped every method (using an eval hack) so that all
changes to its instance varables were passed over to a whole different script
which displayed all the info in a nice neat way. I got 100% seperation of
concern between my generic object and the inteface code to watch it in
action. And this in not only useful for debugging, and what not. Tie that
info to a GUI toolkit script and you can farily easily create GUI front ends
for your program, without touching the original code --simple automated
interaction between object and user.

If you really want to change the how the method works, you do as you
do now, redefining the method itself, possibly renaming the old.

Doing a wrap is little more than calling another method:

def this
print “A”
end

def that
print “(”
this
print “)”
end

I have wrapped this with that. The difference with AOP wrapping is that it
gives you a GENERIC means of accomplishing the same thing. So that all other
methods calling on this do not have to be change to call on that. It isn’t a
big deal in a single class b/c I can just change the insides of this, but
cutting across seperate classes, libraries, programs, etc. That isn’t doable.

I might be wrong though.

Nope not wrong, there’s just even more to it.

-t0

···

On Thursday 27 November 2003 09:13 am, Thomas Fini Hansen wrote:

On Thu, Nov 27, 2003 at 04:57:02PM +0900, T. Onoma wrote:

On Thursday 27 November 2003 08:22 am, Gavin Sinclair wrote:

Peter wrote:

If the arity goes up, you can avoid problems provided the
first arguments remain the same and your hook doesn’t care
about them by using a *arg as in my example…

I feel you gave only very weak argument why in this particular
circumstance the removal shouldn’t happen automatically.

OK, I didn’t realize your argument was in case of arity
changes, just like you didn’t realize my argument was for the
general case. Cool! But seriously, if that particular
circumstance is rare enough, why care?

You realize that you on are speculative grounds claiming that
these circumstances will be rare enough. One of the more common
method redefining circumstances are probably (this base on other
evidence but my gut feeling:-) are of the form

def meth(a,b,c,new_parm = some_default_value)

end

Even if this were to happen rarely, redefining the primary method
in an arity altering way would render the class unusable if the
hooks weren’t removed. Being forced to use reflection features to
remove the hooks is NOT suitable for beginners and I wouldn’t want
to be bothered (perhaps because I never grew nor ever will grow out
of beginner-tum:-) with this either.

(Gee, they already brainwashed me :slight_smile: So you still need to
show that a change in arity happens often enough compared to
say change of implementation. I think that highly depends on
how you write your code, whether you work top-down - first
get the interfaces right, then implement

  • or bottom-up - start implementing small parts and build on
    that to make larger parts. Or whether you combine both.

Also, if you’d change a method and need extra arguments for
extra functionality, then if your hook can’t handle those
extra arguments generically, that’s pretty tight coupling, isn’t it?

Only if suspect that potential customers are likely to redefine
the primary method signature.

/Christoph

Yukihiro Matsumoto wrote:

Hi,

Which one? We have too many “previous” posts here.

the “right before this one” kind of previous :wink:

do i post too much?

No. But I prefer identity by X-Mail-Count (for example, I’m replying
to [ruby-talk:86484]).

  					matz.

FWIW,
Reading the mail list on Mozilla, I don’t even see the X-Mail-Count
unless I turn on all headers, and then I get so many headers that I
can’t see the messages. This may be a criticism of Mozilla, but it does
make it difficult to refer to the X-Mail-Count.

···

In message “Re: Method wrapping” > on 03/11/27, “T. Onoma” transami@runbox.com writes:

T. Onoma wrote:

Actually I have rethought this. Wrappers do depend on the implementation b/c
their proper functionality depends on what is returned, not just what
kind. They may not raise an error if the kinds are the same, but that
doesn’t mean they work right. So my original wording was more correct.

The distinction between what and kind alludes me for the moment.
However, I would tend to suspect that a wrapper depends upon the primary
method in the same way client software depends upon the methods it
calls. In other words, they depend upon the arguments, return value and
semantics (as defined by a DbC style contract), but not upon actual
implementation.

I would suspect that most method replacements would honor the same
argument lists, return types and basic semantics. Otherwise replacing a
method would cause everyone who calls that method to be modified, not
just the wrapper methods.

···


– Jim Weirich jweirich@one.net http://onestepback.org

“Beware of bugs in the above code; I have only proved it correct,
not tried it.” – Donald Knuth (in a memo to Peter van Emde Boas)

What are wrappers going to be used for? Are you only supposed to add
wrappers to your own code? How about keeping some statistics about calls
to some library? I could write a proxy object that does that for me, but
wrappers are more flexible I guess. If I do that, some methods may have my
wrappers wrapped around them, or some of the library’s, or some other
library’s. That sounds plausible, doesn’t it? Then if the wrappers are
removed on redefinition of a method, arranging the wrappers to be
reinstalled is a tough job, and it might not even be necessary if your
wrappers are defined well and the method changes are not at random.
Increasing arity can be caught with a *args in the argument list. I use
that in my initialize methods to call the initialize method in the
superclass. As such, I can add arguments to the initialize method of the
superclass and subclasses can beautifully pass them on without caring how
many there really are.

So my point is then that rarely wrappers would need to be reinstalled if
care is taken. If they do need reinstalling, the code for that isn’t
always obvious and I don’t need my code to be littered with weird,
unnecessary code.

Maybe your misunderstanding me (or vice-versa)? B/C I basically agree with
what you’re sayng. But you don’t have to reinstall the wrappers. You will
just add another wrapper in your case, not replace the “heart” method. Do you
know what I mean? Your saying if it is all “defined well and the method
changes are not at random” then this should be all you need. If you really
find yourself in a position where the “heart” method needs to be changed
without effecting the wrappers (kind of like pulling out a table cloth but
putting one back too) then there is good reason to think that your main
method should actually be in its own superclass. In which case you could
change it and your subclass methods will still be there.

In other words we don’t need to overburden the wrapping mechinism with
functionality we arleady have that more clearly seperates concerns. A method
and its wraps within the same class should be seen as a whole, not separate
methods. So redefining should effect them all.

That’s certainly not the Ruby Way. I’m not sure what kind of method to
use for your case though, perhaps like

selective_def(index, :ameth, *args) do
end

To replace the “heart” you’d use index=0. Hey! Better yet, perhaps we can
have some array like sugar:

def ameth0
end

I think that would work nicely. You?

Like I said, wrappers can get mixed and I don’t want to count on a certain
wrapper being in a certain position in the stack. If wrappers can be
added/removed, e.g., for turning logging on/off, positions change. Keeping
track of those positions is not my idea of good separation of concerns. I
like (optional) identifiers for wrappers better, but that’s apparently
just me…

I agree. I don’t even care for being able to index them at all, but it seems
some people feel we need some way to access them. Indexes don’t require extra
“naming” syntax. But you are right, they would be pain to mange, so only good
for mucking around.

But the naming thing does spark some interesting notions. I will consider this
in detail to figure out how it could/would work. Let you know what I come up
with.

But again, what will be the use of those wrappers? A lot of it will depend
on that. If it’s supposed to be used for modeling cross-cutting concerns
like in AOP, reinstalling wrappers could prove to be awkward.

Maybe I’m just thinking too much about all this…

It’s good to think about b/c it is a actually an additional paradigm for
coding and we should get it right. Have you read my AOP RCR?

-t0

···

On Thursday 27 November 2003 05:44 pm, Peter wrote:

You realize that you on are speculative grounds claiming that
these circumstances will be rare enough. One of the more common
method redefining circumstances are probably (this base on other
evidence but my gut feeling:-) are of the form

def meth(a,b,c,new_parm = some_default_value)

end

def meth:wrap(a,b,*args)
do_something(a, b)
super
end

This WORKS for constructors. Really. And they are a kind of wrappers as
Tom pointed out. Unless you’d give b a default value too…

Even if this were to happen rarely, redefining the primary method
in an arity altering way would render the class unusable if the
hooks weren’t removed. Being forced to use reflection features to
remove the hooks is NOT suitable for beginners and I wouldn’t want
to be bothered (perhaps because I never grew nor ever will grow out
of beginner-tum:-) with this either.

There you’ve got a point. But removing the wrappers could also break other
code, no? Unless you only put code in those wrappers that are not needed
for correct execution…

Peter

We used to put it in the subject (i.e. Subect: Re: [ruby-talk:12345]
Method wrapping), but this caused problems with threading in some mail
readers, and most people agreed it was better to turn it off. We’ve
still retained the same naming scheme for mailing list posts, however.

Paul

···

On Fri, Nov 28, 2003 at 02:17:45AM +0900, Charles Hixson wrote:

FWIW,
Reading the mail list on Mozilla, I don’t even see the X-Mail-Count
unless I turn on all headers, and then I get so many headers that I
can’t see the messages. This may be a criticism of Mozilla, but it does
make it difficult to refer to the X-Mail-Count.

In other words we don’t need to overburden the wrapping mechinism with
functionality we arleady have that more clearly seperates concerns. A method
and its wraps within the same class should be seen as a whole, not separate
methods. So redefining should effect them all.

That would be ideal, but my point was that I don’t see how you are going
to do that in anyone can wrap any method. It would be cool if it were a
whole, but those wrapper can be bits and pieces from more than one
person’s code. You’d need a way to enforce that “affect them all” thingy.

But the naming thing does spark some interesting notions. I will consider this
in detail to figure out how it could/would work. Let you know what I come up
with.

Waiting :slight_smile:

It’s good to think about b/c it is a actually an additional paradigm for
coding and we should get it right. Have you read my AOP RCR?

Nope. But I will then, and let you know how I feel about it.

Peter

Hi,

···

In message “Re: Method wrapping” on 03/11/28, Charles Hixson charleshixsn@earthlink.net writes:

Reading the mail list on Mozilla, I don’t even see the X-Mail-Count
unless I turn on all headers, and then I get so many headers that I
can’t see the messages. This may be a criticism of Mozilla, but it does
make it difficult to refer to the X-Mail-Count.

I do understand the situation, it’s same for me. But still I need
something to identify the message from bunch of posts. As far as I
know, X-Mail-Count is the best identifier.

						matz.

You realize that you on are speculative grounds claiming that
these circumstances will be rare enough. One of the more common
method redefining circumstances are probably (this base on other
evidence but my gut feeling:-) are of the form

def meth(a,b,c,new_parm = some_default_value)

end

Even if this were to happen rarely, redefining the primary method
in an arity altering way would render the class unusable if the
hooks weren’t removed.

Also redefining the primary method means you have to know what the next hook
expects from its output and make sure it gets it:

def birdy; [1,2,3]; end
def birdy:wrap; raise !super === Array; end
def birdy; “1,2,3”; end

If the later just replaces the primary then, bye bye birdy.

Being forced to use reflection features to
remove the hooks is NOT suitable for beginners and I wouldn’t want
to be bothered (perhaps because I never grew nor ever will grow out
of beginner-tum:-) with this either.

Beginner-dom? Me too. :slight_smile:

(Gee, they already brainwashed me :slight_smile: So you still need to
show that a change in arity happens often enough compared to
say change of implementation. I think that highly depends on
how you write your code, whether you work top-down - first
get the interfaces right, then implement

  • or bottom-up - start implementing small parts and build on
    that to make larger parts. Or whether you combine both.

Also, if you’d change a method and need extra arguments for
extra functionality, then if your hook can’t handle those
extra arguments generically, that’s pretty tight coupling, isn’t it?

Only if suspect that potential customers are likely to redefine
the primary method signature.

And, like i said to Peter, if just the primary method needs a’changin, its a
good indication that a superclass is needed.

-t0

···

On Thursday 27 November 2003 05:45 pm, Christoph wrote:

And, like i said to Peter, if just the primary method needs a’changin, its a
good indication that a superclass is needed.

I think I see the cause of the misunderstanding… Your use of method
wrapping is meant to create a complete implementation of a method. Each
wrapper adds extra functionality or changes the signature. A good example
is a basic class that works on bare data, and wrappers are added to pack
and unpack the data, which is really an orthogonal issue. But I would
always have created either adapters for that, or just used helper methods,
although wrapping sounds more convenient to me.

My idea of AOP was a bit different. I wanted to know what AOP was about
and so I attended one of the AspectJ guys’ tutorials, and I guess I’m a
bit biased because of their limited implementation. But the main point in
their talk for using AOP was something like logging. When they add an
aspect to a method, it doesn’t change signature (a signature change in
Java means method overloading I believe). Also you can add aspects to
methods of other people’s classes that don’t add functionality, but just
“hack in” for your own vile purposes. Things like logging or keeping
statistics is a simple example of that (they overuse these examples). And
they are on another level of orthogonality because they don’t necessarily
care about the number of arguments or the type of these arguments. Or they
care about just part of that signature, and with some care that can be
left unchanged by e.g., only adding new arguments at the end.

So my conclusion is that there are two kinds of wrappers: those that make
up the base implementation (i.e., the primary method and its required
wrappers) and wrappers added for “meta-tasks”. The former ones need to be
treated as a whole, but the latter ones do not - again, if taken care. I
agree that the base implementation must go when the primary method is
changed, but not those “meta-task” wrappers. And I do think that removing
the latter automatically will create some hassle, but for the former I
think that it’s OK to do so.

Peter

Peter wrote:

You realize that you on are speculative grounds claiming that these
circumstances will be rare enough. One of the more common method
redefining circumstances are probably (this base on other evidence
but my gut feeling:-) are of the form

def meth(a,b,c,new_parm = some_default_value)

end

def meth:wrap(a,b,*args)
do_something(a, b)
super
end

This will probably be illegal since wrapper arity differs from
the primary arity.

This WORKS for constructors. Really. And they are a kind of
wrappers as Tom pointed out. Unless you’d give b a default
value too…

an arity altering way would render the class unusable if the hooks
weren’t removed. Being forced to use reflection features to remove
the hooks is NOT suitable for beginners and I wouldn’t want to be
bothered (perhaps because I never grew nor ever will grow out of
beginner-tum:-) with this either.

There you’ve got a point. But removing the wrappers could
also break other code, no? Unless you only put code in those

This breakage isn’t as bad - it is “only” a semantic one.

wrappers that are not needed for correct execution…

/Christoph

This will probably be illegal since wrapper arity differs from
the primary arity.

Oh… Is there any specific reason for that? But now you got me wondering,
are you saying then that the signatures must match exactly (like the
number of arguments with default values, whether it’s variable-length,
…)? That sounds restrictive… But then again, what’s the intention of
those wrappers?

Peter

I think I see the cause of the misunderstanding… Your use of method
wrapping is meant to create a complete implementation of a method. Each
wrapper adds extra functionality or changes the signature. A good example
is a basic class that works on bare data, and wrappers are added to pack
and unpack the data, which is really an orthogonal issue. But I would
always have created either adapters for that, or just used helper methods,
although wrapping sounds more convenient to me.

My idea of AOP was a bit different. I wanted to know what AOP was about
and so I attended one of the AspectJ guys’ tutorials, and I guess I’m a
bit biased because of their limited implementation. But the main point in
their talk for using AOP was something like logging. When they add an
aspect to a method, it doesn’t change signature (a signature change in
Java means method overloading I believe). Also you can add aspects to
methods of other people’s classes that don’t add functionality, but just
“hack in” for your own vile purposes. Things like logging or keeping
statistics is a simple example of that (they overuse these examples). And
they are on another level of orthogonality because they don’t necessarily
care about the number of arguments or the type of these arguments. Or they
care about just part of that signature, and with some care that can be
left unchanged by e.g., only adding new arguments at the end.

I see. Yes, that was one of the things I was trying to convey. I’ve read a bit
about AspectJ. And certainly I am no AOP guru or anything, but after learning
about it I quickly realized that it could do more than most people seemed to
think it could. That’s how I was able to design a GUI interface for a program
without touching the original code. It just wrapped things, and thus was able
to “plug-in”, but the original code still ran just fine.

So my conclusion is that there are two kinds of wrappers: those that make
up the base implementation (i.e., the primary method and its required
wrappers) and wrappers added for “meta-tasks”. The former ones need to be
treated as a whole, but the latter ones do not - again, if taken care. I
agree that the base implementation must go when the primary method is
changed, but not those “meta-task” wrappers. And I do think that removing
the latter automatically will create some hassle, but for the former I
think that it’s OK to do so.

I see what your saying. If you have wraps that are just monitoring/logging or
what have you, then you might want to just change the primary function and
still keep all the same “meta-tasks”. I can see that point of view. So
controlling the stack isn’t really the issue, you just need to be able to do
the “table cloth trick”, so to speak. For this I would suggest just a
different method, say, defroot, or something like that.

The question really boils down to which behavior should be the default. I
think treating them as a whole is safer and generally more useful, so would
be the better default. But mind you, I also think def itself should do
wrapping without special syntax (as you may have seen from my AOP wiki page).

-t0

···

On Thursday 27 November 2003 07:46 pm, Peter wrote:

Peter wrote:

This will probably be illegal since wrapper arity differs from the
primary arity.

Oh… Is there any specific reason for that? But now you got
me wondering, are you saying then that the signatures must
match exactly (like the number of arguments with default
values, whether it’s variable-length, …)? That sounds

That was my reading of Matz announcement at least for
the arity part. Personally I don’t see a need for matching
default arguments (in fact any default arguments) since
they could be automatically supplied by the primary method
but you have ask Matz for the definite opinion.

restrictive… But then again, what’s the intention of those wrappers?

/Christoph

I see. Yes, that was one of the things I was trying to convey. I’ve read a bit
about AspectJ. And certainly I am no AOP guru or anything, but after learning
about it I quickly realized that it could do more than most people seemed to
think it could. That’s how I was able to design a GUI interface for a program
without touching the original code. It just wrapped things, and thus was able
to “plug-in”, but the original code still ran just fine.

When I was listening to their tutorial, my feeling was that they kept
giving the same examples of logging and alikes, but that it was capable of
much more - though I couldn’t find a good example. A GUI is indeed a
perfect example :slight_smile: But I guess I’ve been brainwashed by those OOP courses
telling me to use things like publish-subscribe, model-view-controller and
so on for that.

I see what your saying. If you have wraps that are just monitoring/logging or
what have you, then you might want to just change the primary function and
still keep all the same “meta-tasks”. I can see that point of view. So
controlling the stack isn’t really the issue, you just need to be able to do
the “table cloth trick”, so to speak. For this I would suggest just a
different method, say, defroot, or something like that.

OK, but if those “meta-tasks” are combined with a primary method and its
own required wrappers, the defroot should change the primary method + its
wrappers.

The question really boils down to which behavior should be the default. I
think treating them as a whole is safer and generally more useful, so would
be the better default. But mind you, I also think def itself should do
wrapping without special syntax (as you may have seen from my AOP wiki page).

My proposition would have been to let wrappers be “sticky” by default
(sticking to the table cloth :slight_smile: and have an override to make a wrapper
“floating”. If someone makes a “floating” wrapper, he should take care
when designing that wrapper. But since AOP is still in its baby stage -
and I don’t know of an application in a dynamic language like Ruby - I
think only time can tell what’s the way to go. If 2.0 gets it wrong, 3.0
will get it right :slight_smile:

As for def doing wrapping all by itself; I think I like the wrapper
methods better (sorry) because the inconsistency can easily be solved IMO.
Suppose you have class A, a subclass B, and a method foo. Each primary
method foo or wrapper foo:wrap/pre/post is part of a chain as long as they
call super. So the order in the chain is A#foo, all wrappers
foo:wrap/pre/post in A, B#foo, and all wrappers in B (that’s what I’d
expect at least). I don’t see why B#foo can’t be left out from that chain.
A#foo gives a problem, but if B#foo would call super and A didn’t have a
foo method, you have the same problem. It’s consistent in the existant
problems :slight_smile:

Peter

That was my reading of Matz announcement at least for
the arity part. Personally I don’t see a need for matching
default arguments (in fact any default arguments) since
they could be automatically supplied by the primary method
but you have ask Matz for the definite opinion.

My point was about something like this:

def foo(a,b,c=3)
blah
end

def foo:wrap(a,b)
blah blah
super
end

Is foo:wrap invalid or not? If it is, I assume the following foo:wrap is
valid, right?

def foo:wrap(a,b,c)
blah blah
super
end

Either way, we loose the parameter with the default value, either because
it’s always 5 or because we always have to specify a value. Only way is to
repeat the default value in foo:wrap. Unless there’s special behavior for
wrapping methods somewhere.

Peter