Underpinnings of Method Wrapping

Its important that we clearly seperate the issue of “surface” syntax from the
underlying machanics of method wrapping. We can pretty much use any notation
that is decided upon. But then how does it work underneath the hood?

My proposal, irregardless of the (IMHO elegant) syntax it presents, has a
solid and tried implementation behind it. This fact may easily go overlooked.
So i just want to take a second and specify that here.

It works simply by using a natural extension to singletons. In fact, I spent
the day hacking the Ruby source code to implement “meta-singletons”.
Basically, it allows you to define singletons on singletons (on singletons)
etc. This implements a stackable wrap. And it optimizes wraps by only
creating a new metaclass layer when necessary. (see Pickaxe p245 end of
Object-Specific Classes) That’s all there was to it.

If we extend this facility to handle pre and post and give singletons a class
literal syntax, plus some lower level methods for manuipulating the
stack…well, that should do it.

Thoughts?

-t0

Thoughts?

I was wondering about something… AOP is based on the idea of join
points, which you describe nicely in your RCR. There is also a notion of
pointcuts that select a number of join points - possibly specifying them
using wildcards - for adding an aspect. This notion is not present in your
RCR (which didn’t occur to me until I read [ruby-talk:86632]). Why did you
leave it out? With Ruby’s large potential for genericity I would expect
the idea of pointcuts to fit better into Ruby than into Java.

Also the idea of cflow disappeared. I remember that when they introduced
it in their tutorial, it sounded weird and unusable, but then they gave a
quite sensible example of its application. Problem is I can’t remember the
example (things like these get devoured by the black hole in my mind) and
I can’t access my notes until after the weekend. Anyhow, what are your
thoughts on cflow?

Peter

Thoughts?

I was wondering about something… AOP is based on the idea of join
points, which you describe nicely in your RCR. There is also a notion of
pointcuts that select a number of join points - possibly specifying them
using wildcards - for adding an aspect. This notion is not present in your
RCR (which didn’t occur to me until I read [ruby-talk:86632]). Why did you
leave it out? With Ruby’s large potential for genericity I would expect
the idea of pointcuts to fit better into Ruby than into Java.

Actually they fit so well we don’t even need to explictly deal with them! :wink:

I originally had a small paragraph touching on this, but I took it out b/c I
realized that the much of the methods/ideas/terminology used in AOP, as it is
commonly understood, derives from the fact that Java is the “common
denominator” implementation language, which isn’t a dynamic language like
Ruby. Hence they had to implement whole new constructs which they gave funny
names :wink: An aspect for instance is nothing more than a method for
describing where (pointcuts) and what (advices) to insert.

So lets look at a Ruby example:

def aspect_t1(klass)
klass.instance_methods(true).each do |m|
if m =~ /^t/ && klass.instance_method(m).arity==1
puts “Applying advice to #{m}”
klass.class_eval %Q{
def_wrap #{m}
puts “Entering #{m}”
super
puts “Exiting #{m}”
end
}
end
end
end

And I’m sure there are many other ways to go about this. So you see, for Ruby,
implementing aspects and pointcuts really dosen’t require anything new, as
long as we have the join-points.

But that brings us back to your idea for method “indicators”, and now I think
it would be a really really good idea!

def meth:arbitrary_symbol
end

The indicator would become another property of Method class like arity, and
used to “group” methods by some classification. They would provide a flexible
way to determine pointcuts. And an important reason NOT to use def meth:pre
syntax!

Also the idea of cflow disappeared. I remember that when they introduced
it in their tutorial, it sounded weird and unusable, but then they gave a
quite sensible example of its application. Problem is I can’t remember the
example (things like these get devoured by the black hole in my mind) and
I can’t access my notes until after the weekend. Anyhow, what are your
thoughts on cflow?

Honestly, I didn’t quite get cflow. So maybe you can help me out here. It’s a
way to further contrain pointcuts. But based on what? Based on runtime
parameters? What is it doing differently? Given the above, i’m not sure we
need it, anyway.

I can tell you that adding these AOP features, convinces me that we need
special keywords for parameter args, keys and block, that all methods have
accessible, despite what’s in the method argument list. I.e.

def x(x)
puts args
end
x(1) # → [ 1 ]

It only makes sense in order to “aspect” methods generically.

-t0

···

On Saturday 29 November 2003 12:44 am, Peter wrote:

I originally had a small paragraph touching on this, but I took it out b/c I
realized that the much of the methods/ideas/terminology used in AOP, as it is
commonly understood, derives from the fact that Java is the “common
denominator” implementation language, which isn’t a dynamic language like
Ruby. Hence they had to implement whole new constructs which they gave funny
names :wink: An aspect for instance is nothing more than a method for
describing where (pointcuts) and what (advices) to insert.

I now realize that my question was phrased a bit badly… The idea of
applying the same advice to multiple methods - implemented using either
the pointcuts from AspectJ or Ruby’s dynamism - is an important part of
AOP, and I missed the mention of that in your RCR. I was wondering whether
you thought it was either very obvious or not a very good idea. Our recent
discussions on wrapping kind of made it sound like you believe a wrapper
is often highly specific for a method. If that is so, then indeed wrappers
should be removed on primary method definition, but then wrappers won’t
apply to many primary methods either - unless to a method and its subclass
overridden versions.

But that brings us back to your idea for method “indicators”, and now I think
it would be a really really good idea!

def meth:arbitrary_symbol
end

The indicator would become another property of Method class like arity, and
used to “group” methods by some classification. They would provide a flexible
way to determine pointcuts. And an important reason NOT to use def meth:pre
syntax!

In this incarnation, the idea of those “method indicators” reminds me of
the class selector in CSS; even when HTML tags have the same name, they
can be formatted differently depending on the class specification.

Honestly, I didn’t quite get cflow. So maybe you can help me out here. It’s a
way to further contrain pointcuts. But based on what? Based on runtime
parameters? What is it doing differently? Given the above, i’m not sure we
need it, anyway.

cflow basically allows you to say that advice only applies to a method if
it is called directly or indirectly by another method. Suppose you’d want
to do some profiling by counting the number of times a set of methods is
called, but only when the method calls are “triggered” by your own code.
Then you’d add advice to the profiled methods, but it only applies when
they are called directly or indirectly by your own methods, i.e., when it
is in the control flow of your own methods. Does that make sense? But I
need to check the tutorial hand-outs for the example they gave.

Currently it seems to me cflow is only useful for the “meta-tasks” like
profiling and statistics, but maybe you see more general use.

Peter

I originally had a small paragraph touching on this, but I took it out
b/c I realized that the much of the methods/ideas/terminology used in
AOP, as it is commonly understood, derives from the fact that Java is the
“common denominator” implementation language, which isn’t a dynamic
language like Ruby. Hence they had to implement whole new constructs
which they gave funny names :wink: An aspect for instance is nothing more
than a method for describing where (pointcuts) and what (advices) to
insert.

I now realize that my question was phrased a bit badly… The idea of
applying the same advice to multiple methods - implemented using either
the pointcuts from AspectJ or Ruby’s dynamism - is an important part of
AOP, and I missed the mention of that in your RCR. I was wondering whether
you thought it was either very obvious or not a very good idea.

The join-points are the only thing required to facilitate all of this. So I
did not think it neccessary to elaborate on. I will go back a mention it
though. Just to be clear, the method I used with “Ruby’s dynamism” provides
pointcuts. Its not that Java has pointcuts and Ruby doesn’t. Only that Ruby
doesn’t need special syntax to do pointcuts (in fact it probably would be
more limited even if it did).

Our recent discussions on wrapping kind of made it sound like you believe a
wrapper is often highly specific for a method. If that is so, then indeed
wrappers should be removed on primary method definition, but then wrappers
won’t apply to many primary methods either - unless to a method and its
subclass overridden versions.

Not exactly, they can be both, and the whole spectrum inbetween. This is a
tough question. Take for instance a common form of doing very simple
plug-ins: subclassing. When you make a subclass you’ll redefine some methods
to get the new behavior desired. When you do this, if the wrappers in the
superclass in any way effect function, then “99 times out of 100” the
wrappers will have to go. But if they’re just to observe, like logging, then
you may still want them, you may not. In the end, I think we really need to
support both scenarios. My problem though, is that most people only see the
logging abilities of AOP, and don’t realize there’s much much more you can do
with it, so they think, “of course keep the wrappers”, but when you really
start to take advantage of AOP’s power to do more than this, that’s when
you’ll start thinking, “why do I have to keep flushing these wrappers!”.
Moreover, not flushing them by default, will only promote the idea that AOP
is only good for logging type applications. So I think it much better to
flush by default --we can still offer “table clothing” with a simple extra
keyword.

But that brings us back to your idea for method “indicators”, and now I
think it would be a really really good idea!

def meth:arbitrary_symbol
end

The indicator would become another property of Method class like arity,
and used to “group” methods by some classification. They would provide a
flexible way to determine pointcuts. And an important reason NOT to use
def meth:pre syntax!

In this incarnation, the idea of those “method indicators” reminds me of
the class selector in CSS; even when HTML tags have the same name, they
can be formatted differently depending on the class specification.

That’s it exactly. Anyone who’s done a lot of html work knows the advantage of
CSS. This would give that same advantage to Ruby’s AOP features.

Honestly, I didn’t quite get cflow. So maybe you can help me out here.
It’s a way to further contrain pointcuts. But based on what? Based on
runtime parameters? What is it doing differently? Given the above, i’m
not sure we need it, anyway.

cflow basically allows you to say that advice only applies to a method if
it is called directly or indirectly by another method. Suppose you’d want
to do some profiling by counting the number of times a set of methods is
called, but only when the method calls are “triggered” by your own code.
Then you’d add advice to the profiled methods, but it only applies when
they are called directly or indirectly by your own methods, i.e., when it
is in the control flow of your own methods. Does that make sense? But I
need to check the tutorial hand-outs for the example they gave.

This reminds me of an RCR I put in once. I suggested that every object have a
keyword reference back to its “brith parent”. So if I cerated object foo =
Foo.new from within object bar, foo#parent would reference bar. In this case
it seems their might be good reason for each method to have a keyword method
(Method#cflow) referenceing the method object it was called from. In that way
I think we could offer cflow support.

I think a lot of this is pointing to the simple fact that Ruby needs to make
its Methods more capable and introspective, much in the same way that
classes/objects are. For instance, cflow, and my suggestion for built-in
keywords for args, keys and block, plus a way to see what class/module the
method is in (from the inside out, we can already do from the outside in),
and so on. Having such capabilities helps exploit the full potential of AOP.

Currently it seems to me cflow is only useful for the “meta-tasks” like
profiling and statistics, but maybe you see more general use.

I cann see it to some degree: off the top of my head: If the method #kill was
called from method #hunt, then you might want to trigger the method
#excitement, but if the same method #kill was called from #protect_thyself,
then it should instead trigger #relief. Very abstract, but I think it paints
the proper idea.

-t0

P.S. So what did you think of the singleton foundation?

···

On Saturday 29 November 2003 04:26 pm, Peter wrote:


Ethics 101: Don’t RIP without proper Props

The join-points are the only thing required to facilitate all of this. So I
did not think it neccessary to elaborate on. I will go back a mention it
though. Just to be clear, the method I used with “Ruby’s dynamism” provides
pointcuts. Its not that Java has pointcuts and Ruby doesn’t. Only that Ruby
doesn’t need special syntax to do pointcuts (in fact it probably would be
more limited even if it did).

Oh, I agree completely, Ruby will be able to specify the most general
pointcuts possible since you can specify it in code. Any code. Wildcards
is limiting. Though maybe I should mention that the AspectJ guys said
nobody ever missed anything more general then wildcards in AspectJ.

Not exactly, they can be both, and the whole spectrum inbetween. This is a
tough question. Take for instance a common form of doing very simple
plug-ins: subclassing. When you make a subclass you’ll redefine some methods
to get the new behavior desired. When you do this, if the wrappers in the
superclass in any way effect function, then “99 times out of 100” the
wrappers will have to go. But if they’re just to observe, like logging, then
you may still want them, you may not. In the end, I think we really need to
support both scenarios. My problem though, is that most people only see the
logging abilities of AOP, and don’t realize there’s much much more you can do
with it, so they think, “of course keep the wrappers”, but when you really
start to take advantage of AOP’s power to do more than this, that’s when
you’ll start thinking, “why do I have to keep flushing these wrappers!”.
Moreover, not flushing them by default, will only promote the idea that AOP
is only good for logging type applications. So I think it much better to
flush by default --we can still offer “table clothing” with a simple extra
keyword.

I agree we should support both scenarios. But I don’t agree yet on
discarding wrappers by default. Aspects are supposed to model orhtogonal
aspects of an application and are supposed to be uncoupled. Which means
wrapper and wrappee ought to be uncoupled. But maybe that’s one of those
cool ideas that are infeasible in practice. And the use of method
combination may not be limited to AOP…

This reminds me of an RCR I put in once. I suggested that every object have a
keyword reference back to its “brith parent”. So if I cerated object foo =
Foo.new from within object bar, foo#parent would reference bar. In this case
it seems their might be good reason for each method to have a keyword method
(Method#cflow) referenceing the method object it was called from. In that way
I think we could offer cflow support.

Yes, except that Method#cflow will only allow looking back one step in the
calling stack. In AspectJ, cflow looks back along the complete calling
stack, which is quite expensive to do if you’d use a Method#cflow for
looking at the calling method. Actually AspectJ’s implementation can be
done in Ruby using only wraps as follows:

def foo
# …
end

def foo
oldInFooCFlow = $inFooCFlow
$inFooCFlow = true
super
$inFooCFlow = oldInFooCFlow
end

def bar
# …
end

def bar
if $inFooCFlow
# advice added to bar in the cflow of foo
end
super
if $inFooCFlow
# advice added to bar in the cflow of foo
end
end

I used your RCR syntax. And forgive me the use of the global var, but that
least clutters the point. So it is possible foo calls some foo2, which
calls some foo3, … until eventually bar is called, and it will work
without the need for looking all the way back up the call stack.

As for the use of the global variable, in AspectJ this is easily done.
Every aspect in AspectJ is a singleton, with its own data members, and all
the advice from that aspect (read: wraps) can access these data members.
As such it effectively provides global, yet private variables.

I think a lot of this is pointing to the simple fact that Ruby needs to make
its Methods more capable and introspective, much in the same way that
classes/objects are. For instance, cflow, and my suggestion for built-in
keywords for args, keys and block, plus a way to see what class/module the
method is in (from the inside out, we can already do from the outside in),
and so on. Having such capabilities helps exploit the full potential of AOP.

Agreed.

I cann see it to some degree: off the top of my head: If the method #kill was
called from method #hunt, then you might want to trigger the method
#excitement, but if the same method #kill was called from #protect_thyself,
then it should instead trigger #relief. Very abstract, but I think it paints
the proper idea.

I understand. It offers a way to find out about the callers of a method -
or more abstract: the context of a call. Though the abstract idea sounds
mighty interesting, I’m not so crazy about using method names to find out
about the context. But I don’t know about a better way. Just weird that
you have to name your method in a particular way to get the right behavior
from a method you’re calling.

Peter

P.S. So what did you think of the singleton foundation?

Are you referring to the line “wraps act very much like singletons” from
your RCR? In that case, I think I missed the point. But that’s probably
because it was the explanation to something that’s so obvious to me :slight_smile:

Oh, I agree completely, Ruby will be able to specify the most general
pointcuts possible since you can specify it in code. Any code. Wildcards
is limiting. Though maybe I should mention that the AspectJ guys said
nobody ever missed anything more general then wildcards in AspectJ.

How would they know? :wink:

I agree we should support both scenarios. But I don’t agree yet on
discarding wrappers by default. Aspects are supposed to model orhtogonal
aspects of an application and are supposed to be uncoupled. Which means
wrapper and wrappee ought to be uncoupled. But maybe that’s one of those
cool ideas that are infeasible in practice. And the use of method
combination may not be limited to AOP…

I’m had some varying thoughts on this. But I think I’ve come to a good
solution. First let me point out that, although unmentioned in my RCR, I’m
all for pre and post, and actually, I’m now in favor of dblack’s suggestion
of simply using pre and post as keywords [yes, db, bygones &c.] b/c they are
ONLY for “meta-tasks” and can’t get invovled in the underlying exectution; so
in this manner they are quite distinct from def. In other words, defs “get in
line” while pres and posts “hang about”, if you take my meaning. In light of
this, it seems appropriate for redef to flush the wrap stack, but all pre’s
and post’s still remain. So we have proper seperation of these concerns: pre
and post for extrinsic, def wrap for intrinsic.

This reminds me of an RCR I put in once. I suggested that every object
have a keyword reference back to its “brith parent”. So if I cerated
object foo = Foo.new from within object bar, foo#parent would reference
bar. In this case it seems their might be good reason for each method to
have a keyword method (Method#cflow) referenceing the method object it
was called from. In that way I think we could offer cflow support.

Yes, except that Method#cflow will only allow looking back one step in the
calling stack. In AspectJ, cflow looks back along the complete calling
stack, which is quite expensive to do if you’d use a Method#cflow for
looking at the calling method.

Is it very expensive? ameth.cflow.cflow… hmmm, I guess your right, if your
looking for a method that could be anywhere up the reference list. Although I
think in practice the list will only get so long. (And shortcutted for
recursive calls). But I definitely see your point (though I think
Method#cflow would still have its uses).

Actually AspectJ’s implementation can be
done in Ruby using only wraps as follows:

def foo
# …
end

def foo
oldInFooCFlow = $inFooCFlow
$inFooCFlow = true
super
$inFooCFlow = oldInFooCFlow
end

def bar
# …
end

def bar
if $inFooCFlow
# advice added to bar in the cflow of foo
end
super
if $inFooCFlow
# advice added to bar in the cflow of foo
end
end

I used your RCR syntax. And forgive me the use of the global var, but that
least clutters the point. So it is possible foo calls some foo2, which
calls some foo3, … until eventually bar is called, and it will work
without the need for looking all the way back up the call stack.

I noticed right away that you were using my syntax :slight_smile: I’ve heard so many
people say how ridiculous such a syntax is (funny that they keep mentioning
it), but right now I can tell you it feels completely natural --seeing the
defs come in order parallels their stacking order. Anyway…

As for the use of the global variable, in AspectJ this is easily done.
Every aspect in AspectJ is a singleton, with its own data members, and all
the advice from that aspect (read: wraps) can access these data members.
As such it effectively provides global, yet private variables.

Definitely, and I’m certain we can achieve the same thing with module’s and
their instance variables. Define a module containing aspect methods and the
module variables they need and apply as desired. Hell, we can even wrap the
aspect methods!

I think a lot of this is pointing to the simple fact that Ruby needs to
make its Methods more capable and introspective, much in the same way
that classes/objects are. For instance, cflow, and my suggestion for
built-in keywords for args, keys and block, plus a way to see what
class/module the method is in (from the inside out, we can already do
from the outside in), and so on. Having such capabilities helps exploit
the full potential of AOP.

Agreed.

Have to add to RCR.

I cann see it to some degree: off the top of my head: If the method #kill
was called from method #hunt, then you might want to trigger the method
#excitement, but if the same method #kill was called from
#protect_thyself, then it should instead trigger #relief. Very abstract,
but I think it paints the proper idea.

I understand. It offers a way to find out about the callers of a method -
or more abstract: the context of a call. Though the abstract idea sounds
mighty interesting, I’m not so crazy about using method names to find out
about the context. But I don’t know about a better way. Just weird that
you have to name your method in a particular way to get the right behavior
from a method you’re calling.

Ah…but this is what the indicators are for.

def eat:eating
end

def gorge:eating
end

def stuffyourface:eating
end

We can aspect all the eating methods. ( no, i’m not hungry :slight_smile:

Peter

P.S. So what did you think of the singleton foundation?

Are you referring to the line “wraps act very much like singletons” from
your RCR? In that case, I think I missed the point. But that’s probably
because it was the explanation to something that’s so obvious to me :slight_smile:

I really need to go back and specify this. It was still a little fuzzy in my
mind when I started the RCR, but now it’s quite clear --perfectly clear. So
much so that I pulled up the Ruby source and hacked it in. Changed about 6
lines of code and got it working, albiet it still needs TLC to fix-up and add
all the bells and whistles, but the proof is in pudding, and I got pudding.

But I’m getting ahead of myself. I need to explain the point. Lets take this
example:

class Classic
def x
print “X”
end
end
c = Classic.new
def c.x
print “(”
super
print “)”
end
c.x; puts # => (X)

We have created an object c, that has a method x, then we defined a singleton
also called x. The singleton effectively wraps the original method. This is
explained well in the Pickaxe. Check out page 246, Fig. 19.3. The diagram is
describe a couple pages back under Object-Specific Class; or you can surf
here:

http://www.rubycentral.com/book/classes.html

So then what happens if we try to add another singleton of the same name?

def c.x
print “[”
super
print “]”
end
c.x; puts # =>

Why didn’t it wrap again? Let me quote the end of that Pickaxe section:

“Ruby performs a slight optimization with these singleton classes. If an
object’s klass reference already points to a singleton class, a new one will
not be created.”

Obviously when Matz created this, it didn’t occur to him that unlimted
wrapping may be useful. He just saw that it was wasted overhead to have a
separate singleton class for each and every singleton method. But his
optimization had the above side effect --you can only define one layer. So I
went back and changed the optimization such that when a method of the same
name already exists in the singleton class, a new singleton class (metaclass
in the code) is created. So my version of Ruby instead does the following:

def c.x
print “[”
super
print “]”
end
c.x; puts # => [(X)]

That’s all there was to it, and it serves as the perfect starting point/basis
for building all the rest of the AOP features.

-t0

···

On Sunday 30 November 2003 01:01 am, Peter wrote:

This works fine with singletons, but there is a problem if you want to
do it for “normal” instance methods (i.e. wrapping the method for all
objects of a given class), see [ruby-talk:75334] for an explanation and
[ruby-talk:75290] for an implementation using an explicit indication
“plz make this method available with super after redefinition”.

···

On Sun, Nov 30, 2003 at 11:53:25AM +0900, T. Onoma wrote:

But I’m getting ahead of myself. I need to explain the point. Lets take this
example:

class Classic
def x
print “X”
end
end
c = Classic.new
def c.x
print “(”
super
print “)”
end
c.x; puts # => (X)


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’ \
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Never make any mistaeks.
– Anonymous, in a mail discussion about to a kernel bug report

How would they know? :wink:

The all-seeing eye? I believe they got feedback from a number of large
projects that used AspectJ.

I’m had some varying thoughts on this. But I think I’ve come to a good
solution. First let me point out that, although unmentioned in my RCR, I’m
all for pre and post, and actually, I’m now in favor of dblack’s suggestion
of simply using pre and post as keywords [yes, db, bygones &c.] b/c they are
ONLY for “meta-tasks” and can’t get invovled in the underlying exectution; so
in this manner they are quite distinct from def. In other words, defs “get in
line” while pres and posts “hang about”, if you take my meaning. In light of
this, it seems appropriate for redef to flush the wrap stack, but all pre’s
and post’s still remain. So we have proper seperation of these concerns: pre
and post for extrinsic, def wrap for intrinsic.

I like the proper separation, but why pre and post for extrinsic and def
wrap for intrinsic?

Is it very expensive? ameth.cflow.cflow… hmmm, I guess your right, if your
looking for a method that could be anywhere up the reference list. Although I
think in practice the list will only get so long. (And shortcutted for
recursive calls). But I definitely see your point (though I think
Method#cflow would still have its uses).

Yup, the call stack in general is pretty small, except in case of a
recursive algorithm. But mutually recursive methods complicate things a
bit for any shortcut :wink:

I noticed right away that you were using my syntax :slight_smile: I’ve heard so many
people say how ridiculous such a syntax is (funny that they keep mentioning
it), but right now I can tell you it feels completely natural --seeing the
defs come in order parallels their stacking order. Anyway…

Agreed, but these are small examples. What if a primary method and its
wraps are dispersed throughout the source code?

Definitely, and I’m certain we can achieve the same thing with module’s and
their instance variables. Define a module containing aspect methods and the
module variables they need and apply as desired. Hell, we can even wrap the
aspect methods!

:slight_smile: But one aspect adding advice to methods in more than one class is -
though perfectly possible - more complicated, unless I’m overlooking
something obvious.

Ah…but this is what the indicators are for.

def eat:eating
end

def gorge:eating
end

def stuffyourface:eating
end

We can aspect all the eating methods. ( no, i’m not hungry :slight_smile:

Grand! Can we specify multiple indicators when calling multiple methods
with different indicator demands?

But I’m getting ahead of myself. I need to explain the point. Lets take this
example:

class Classic
def x
print “X”
end
end
c = Classic.new
def c.x
print “(”
super
print “)”
end
c.x; puts # => (X)

We have created an object c, that has a method x, then we defined a singleton
also called x. The singleton effectively wraps the original method. This is
explained well in the Pickaxe. Check out page 246, Fig. 19.3. The diagram is
describe a couple pages back under Object-Specific Class; or you can surf
here:

http://www.rubycentral.com/book/classes.html

Ah, that kind of singletons… But it confuses me that you are calling the
method the singleton. Isn’t c the singleton, with its own singleton class
in which the method x is put?

So then what happens if we try to add another singleton of the same name?

def c.x
print “[”
super
print “]”
end
c.x; puts # =>

Why didn’t it wrap again? Let me quote the end of that Pickaxe section:

“Ruby performs a slight optimization with these singleton classes. If an
object’s klass reference already points to a singleton class, a new one will
not be created.”

Obviously when Matz created this, it didn’t occur to him that unlimted
wrapping may be useful. He just saw that it was wasted overhead to have a
separate singleton class for each and every singleton method. But his
optimization had the above side effect --you can only define one layer. So I
went back and changed the optimization such that when a method of the same
name already exists in the singleton class, a new singleton class (metaclass
in the code) is created. So my version of Ruby instead does the following:

def c.x
print “[”
super
print “]”
end
c.x; puts # => [(X)]

That’s all there was to it, and it serves as the perfect starting point/basis
for building all the rest of the AOP features.

OK, but my reading of singletons was always as follows. When a singleton
is created, it gets its own singleton class that is a subclass of the
original class. The added method goes in the singleton class. If I define
c.x, it is put in the singleton class, and super is a call to the method
in its superclass, in this case Classic. Defining another c.x just
redefines the method in the singleton class, and super still calls
Classic#x. This would be consistent with explicitly creating the singleton
class, say Classic_c, and redefining Classic_c#x. In this interpretation,
Matz’s optimization is completely valid. But it could also be that I
interpreted it that way because that’s consistent with the optimization…

Peter

Thank you very much for pointing this post out. It contains a very interesting
point that requires some close analysis. In doing so we will discover that it
is actually a little short sighted, but nonetheless hints at a very
interesting direction for extending the capabilites of mixins, that is
subequently the basis for class definable singletons. Let me explain.

The first thing to notice is that Matz’ solution only solves the proposed
problem to one degree, i.e. for one layer of wrapping. Beyond that you run
into the same issue --if Array had also defined each:before (now each:pre)
then the order of occurance would again be the only available criteria for
determining the wrap stack order. So even with Matz’s solution the problem is
not solved for the general case.

One could also argue, that the problem itself is a bit dubious, b/c #each is
not defined by Enumerabe, but rather defines methods that utilize #each as
given by other classes that mixin Enumerable. Moreover, by their very nature
Mixins do not prepend, like singletons, but rather append, like superclasses.
So the notion is a bit misconceived from the get-go. But I am not one to
nitpick such “excuses”! It is understandable that one might think of doing
something like this as a convenient way to aspect classes that partake of
Enumerability. So…

To accomplish this means we must somehow overcome the fact that Mixins only
append. Take this working “hack-up”:

class Array
def testing
print “T”
end
end

enum = Enumerable.dup
enum.module_eval {
def each
print “before”
super
end
def testing
print “(”
super
print “)”
end
}

a = [1,2]
a.extend(enum)
a.each { |i| print i }; puts # => before12
a.testing; puts $ => (T)

This achieves the desired result becasue we have prepended the Enumerable
module to the Array using extend, as opposed to the “under the hood”
appending that occurs with ‘include Enumerable’.

So what would it take to generalize this in a class definable way? It is of
course, essentially the same means that is required to generalize singleton
definitions in a class defineable way. In the particluar case of Mixins, an
interesting possibility comes to mind:

module Enumerable
prepend # <= keyword
def each
puts “before”
super
end
# prepend :each # <= maybe an additional way to do it
end

So everything following the prepend keyword would be prepended as “mixin
singleton class” rather then appended as “mixin superclasss”. And so are
problem is solved in all cases.

···

On Sunday 30 November 2003 10:38 am, Mauricio Fernández wrote:

This works fine with singletons, but there is a problem if you want to
do it for “normal” instance methods (i.e. wrapping the method for all
objects of a given class), see [ruby-talk:75334] for an explanation and
[ruby-talk:75290] for an implementation using an explicit indication
“plz make this method available with super after redefinition”.


On a side note, it is interesting to consider the fact that we don’t have the
keyword super for classes and modules.

class Array
super

end

So that without super we could completely redefine Array, while with super, it
would mean we are adding to it, as we currently do. As it stands, I wonder,
is there even a way to wholly and easily redefine any built-in class or
module? A way does not immediately come to mind, albiet this is something
that would be extremely rare anyway.


It should be apparent enough by now that much of what I’m proposing is greater
uniformity in the way methods, classes, and modules are defined and
manipulated. There is no doubt in my mind that this would make Ruby a better
language. Take a look at the general criteria of a good language as given by
Lambda the Ultimate and you will see Uniformity as second on the list under
Simplicity.

  1. Simplicity
  2. Uniformity
  3. Orthogonality

from http://lambda.weblogs.com/criteria

-t0

I like the proper separation, but why pre and post for extrinsic and def
wrap for intrinsic?

Hmm, not sure how you’re asking. Why different keywords? Or why different use?
I’ll just spell out in detail: I think that pre and post are different enough
from def to warrant there own distinct keywords becuase pre and post can’t
change the method parameters or alter the return value, which def can.

def eat(x)
return x
end

def eat(x)
x.pop
x = super
return x << “BREAD”
end

pre eat
print “I can’t change the fact that I’m being told to eat #{x}.”
end

post eat
print “Nor say I did otherwise, as I also eat some #{x.last}.”
end

Notice that the parameters are not required for pre and post since they can’t
alter anything about the def, only “observe”. (Actually I’m not sure what the
plan on pre and post parameters is.) Its not a big deal really, just makes
the syntax a little cleaner perhaps. defpre, def_pre, predef, pre_def, etc.
any of them would work as well.

Yup, the call stack in general is pretty small, except in case of a
recursive algorithm. But mutually recursive methods complicate things a
bit for any shortcut :wink:

eew, that could bite.

I noticed right away that you were using my syntax :slight_smile: I’ve heard so many
people say how ridiculous such a syntax is (funny that they keep
mentioning it), but right now I can tell you it feels completely natural
–seeing the defs come in order parallels their stacking order. Anyway…

Agreed, but these are small examples. What if a primary method and its
wraps are dispersed throughout the source code?

Realize that your only saving yourself from distingusihing a single layer of
wraps. After that you’re back to the same thing anyway:

def eat(x)
return x
end

defwrap eat(x)
x.pop
x = super
return x << “BREAD”
end

defwrap eat(x)
x = super
return x << “WINE”
end

You’ve only mangaged to defer the issue one step, while adding extra syntax in
the process. One might argue that the first layer is the most common case,
but is that really compelling enough? Perhaps it is when combined with 100%
back compatability. But I think the more uniform syntax is worth it. The
cases in which it does back break compability, the fix is so simple, a patch
tool could be easy written to fix all such code automatically. Also realize
that not using the more uniform case means more variations the interpretor
must account for (i.e. a wrap is given but no def, etc.) Even so, I’m not
going to make a big stink about it either way. There are more important
issues to ensure make it into future Ruby AOP, such as super wrapping and
indicator tags and all the other stuff we’ve been talking about.

Definitely, and I’m certain we can achieve the same thing with module’s
and their instance variables. Define a module containing aspect methods
and the module variables they need and apply as desired. Hell, we can
even wrap the aspect methods!

:slight_smile: But one aspect adding advice to methods in more than one class is -
though perfectly possible - more complicated, unless I’m overlooking
something obvious.

Considering you could hit every thing up using Object, plus common Mixins like
Enumberable. That goes a long way. No doubt to be selective, well, you have
to be selective one way or another. Right? So I’m not sure how you can do
otherwise anyway. You have a specific notion in mind?

Ah…but this is what the indicators are for.

def eat:eating
end

def gorge:eating
end

def stuffyourface:eating
end

We can aspect all the eating methods. ( no, i’m not hungry :slight_smile:

Grand! Can we specify multiple indicators when calling multiple methods
with different indicator demands?

Just to be clear, the indicators are just “tags”, one still calls the method
using just #eat, for instance. So if your asking can we do:

def eat:eating:consuming

end

I’d don’t see why not (an array of indicators?) But keep in mind you can
always do pattern matching on the symbol:

method(eat).to_s.tag =~ /consuming/

So I don’t know if we really need to do beyond a single indicator symbol.

Ah, that kind of singletons… But it confuses me that you are calling the
method the singleton. Isn’t c the singleton, with its own singleton class
in which the method x is put?

Sorry. I use it both ways: A singleton method is just a method that belongs to
a singleton class.

OK, but my reading of singletons was always as follows. When a singleton
is created, it gets its own singleton class that is a subclass of the
original class. The added method goes in the singleton class. If I define
c.x, it is put in the singleton class, and super is a call to the method
in its superclass, in this case Classic. Defining another c.x just
redefines the method in the singleton class, and super still calls
Classic#x. This would be consistent with explicitly creating the singleton
class, say Classic_c, and redefining Classic_c#x. In this interpretation,
Matz’s optimization is completely valid. But it could also be that I
interpreted it that way because that’s consistent with the optimization…

Yes, that is the optimization. You can see it clearly in the sourse code. It
checks to see if the object is already pointing to a singleton or not, if it
is it reuses the same class. I changed it to check to see if the method is
already in the singleton class, if so it makes a “singleton for the
singleton” (further subclass). So we still have the optimiztion, just not
when the method’s previously defined.

-t0

···

On Sunday 30 November 2003 03:57 pm, Peter wrote:

I like the proper separation, but why pre and post for extrinsic and def
wrap for intrinsic?

Hmm, not sure how you’re asking. Why different keywords? Or why different use?
I’ll just spell out in detail: I think that pre and post are different enough
from def to warrant there own distinct keywords becuase pre and post can’t
change the method parameters or alter the return value, which def can.

Never mind, I think I’ve answered my own question in meanwhile. pre and
post can’t alter the result of the method calls, which makes them ideal
for the “meta-tasks” (extrinsic). def can alter the semantics of a method
which makes them ideal for the intrinsic part. But it might sometimes be
convenient to use def even for something extrinsic because of something
like this:

def foo(*args)
# set a here, do other stuff not affecting the super call
result = super
# use a here, do other stuff not affecting the result
result
end

There are more important issues to ensure make it into future Ruby AOP,
such as super wrapping and indicator tags and all the other stuff we’ve
been talking about.

Rite. Let’s drop that other subject then. Bang, boink, clang - it’s
dropped!

Considering you could hit every thing up using Object, plus common Mixins like
Enumberable. That goes a long way. No doubt to be selective, well, you have
to be selective one way or another. Right? So I’m not sure how you can do
otherwise anyway. You have a specific notion in mind?

I think we misunderstood each other again, but correct me if I’m wrong. I
think you thought I meant adding the same aspect to methods in different
classes, right? I meant adding different advice to methods in different
classes but share the same “private, yet global vars”.

Just to be clear, the indicators are just “tags”, one still calls the method
using just #eat, for instance.

Yes, of course. But if tags are used as an indicator to add certain
advice, we might want to indicate that multiple different “advices” apply
to the same method, hence multiple tags.

So if your asking can we do:

def eat:eating:consuming

end

I’d don’t see why not (an array of indicators?) But keep in mind you can
always do pattern matching on the symbol:

method(eat).to_s.tag =~ /consuming/

So I don’t know if we really need to do beyond a single indicator symbol.

I’m short-sighted as usual, you’re right :slight_smile:

Yes, that is the optimization. You can see it clearly in the sourse code. It
checks to see if the object is already pointing to a singleton or not, if it
is it reuses the same class. I changed it to check to see if the method is
already in the singleton class, if so it makes a “singleton for the
singleton” (further subclass). So we still have the optimiztion, just not
when the method’s previously defined.

I understand. I just tried to say that the original implementation seemed
natural to me.

class A
def foo
print “foo”
end
end

c = A.new

def c.foo
print “(”
super
print “)”
end

def c.foo
print “[”
super
print “]”
end

c.foo # [foo]

This to me is just the same as doing:

class A
def foo
print “foo”
end
end

class A_c < A
def foo
print “(”
super
print “)”
end
end

class A_c
def foo
print “[”
super
print “]”
end
end

c = A_c.new

c.foo # [foo]

I admit, this makes the second foo look like a wrapping and the third like
a redefinition. But this is consistent with the idea that each object gets
its own singleton class (though in the implementation it is only created
when necessary), and defining object.foo is like adding the method to
object’s singleton class. The Pickaxe doesn’t say it this way, but instead
goes into detail of implementation. But that was my way of thinking about
it on an abstract level that is consistent with the implementation, and
there was no wrapper idea involved. That’s what I tried to say. But if you
really look at it as some wrapping mechanism, your new implementation
makes more sense.

Peter

Hi,

···

At Sun, 30 Nov 2003 21:40:52 +0900, T. Onoma wrote:

On a side note, it is interesting to consider the fact that we don’t have the
keyword super for classes and modules.

class Array
super

end

So that without super we could completely redefine Array, while with super, it
would mean we are adding to it, as we currently do. As it stands, I wonder,
is there even a way to wholly and easily redefine any built-in class or
module? A way does not immediately come to mind, albiet this is something
that would be extremely rare anyway.

Different super class makes different class.

class Array < Class.new
end


Nobu Nakada

Never mind, I think I’ve answered my own question in meanwhile. pre and
post can’t alter the result of the method calls, which makes them ideal
for the “meta-tasks” (extrinsic). def can alter the semantics of a method
which makes them ideal for the intrinsic part. But it might sometimes be
convenient to use def even for something extrinsic because of something
like this:

def foo(*args)
# set a here, do other stuff not affecting the super call
result = super
# use a here, do other stuff not affecting the result
result
end

You’re absolutely right. Hmm…Granted this is acting in accordance to an
intrinsic wrap, buit it’s not gaurenteed. So this is fine, but if foo is
later redefined this wrap will be flushed (at least IMHO it should be). But
we need to solve the problem you present., so either pre and post must be
considered essentially connected in scope with access to the same vars, which
seems rather odd, or we can just have an intrinstic wrap defintion like:

wrap foo(*args)
# set a here, do other stuff not affecting the super call
result = psudeo_super
# use a here, do other stuff not affecting the result
end

Then we don’t need pre or post. I suppose if no “psuedo_super” is given it
would be assumed to be like a pre? I’m not sure. What do you think?

I think we misunderstood each other again, but correct me if I’m wrong. I
think you thought I meant adding the same aspect to methods in different
classes, right? I meant adding different advice to methods in different
classes but share the same “private, yet global vars”.

Your right. Sorry. But I do think sime of the same basic methods apply. Not
sure. I guess I need some examples to really be able to consider.

method(eat).to_s.tag =~ /consuming/

So I don’t know if we really need to do beyond a single indicator symbol.

I’m short-sighted as usual, you’re right :slight_smile:

Ha! You should see how thick my glasses are! :slight_smile:

This to me is just the same as doing:

class A
def foo
print “foo”
end
end

class A_c < A
def foo
print “(”
super
print “)”
end
end

class A_c
def foo
print “[”
super
print “]”
end
end

c = A_c.new

c.foo # [foo]

I admit, this makes the second foo look like a wrapping and the third like
a redefinition.

I hold my tounge :wink:

But this is consistent with the idea that each object gets
its own singleton class (though in the implementation it is only created
when necessary), and defining object.foo is like adding the method to
object’s singleton class. The Pickaxe doesn’t say it this way, but instead
goes into detail of implementation. But that was my way of thinking about
it on an abstract level that is consistent with the implementation, and
there was no wrapper idea involved. That’s what I tried to say. But if you
really look at it as some wrapping mechanism, your new implementation
makes more sense.

I think you’re right on. My implementation, instead, just adds more of the
same:

class A
def foo
print “foo”
end
end

class A_c < A
def foo
print “(”
super
print “)”
end
end

class A_cc < A_c
def foo
print “[”
super
print “]”
end
end

c = A_cc.new

c.foo # [(foo)]

-t0

···

On Sunday 30 November 2003 09:39 pm, Peter wrote:

Thanks nobu. That makes sense.

BTW does this mean if I redefine Array the literal form will use my new class?

class Array < MyArray
end

[1,2,3].kind_of?(MyArray) # => true

···

On Monday 01 December 2003 01:55 am, nobu.nokada@softhome.net wrote:

Different super class makes different class.

class Array < Class.new
end

You’re absolutely right. Hmm…Granted this is acting in accordance to an
intrinsic wrap, buit it’s not gaurenteed. So this is fine, but if foo is
later redefined this wrap will be flushed (at least IMHO it should be). But
we need to solve the problem you present., so either pre and post must be
considered essentially connected in scope with access to the same vars, which
seems rather odd, or we can just have an intrinstic wrap defintion like:

wrap foo(*args)
# set a here, do other stuff not affecting the super call
result = psudeo_super
# use a here, do other stuff not affecting the result
end

Then we don’t need pre or post. I suppose if no “psuedo_super” is given it
would be assumed to be like a pre? I’m not sure. What do you think?

First a note: I think intrinsic and extrinsic got swapped between the
first mention of it and now. Maybe we should try to get these things
straight to avoid unnecessary misunderstandings. A wrap was intrinsic,
because it was an intrinsic part of the semantics of a method, and pre and
post were extrinsic because they were really just riding along quietly.
That sounds logical to me. By this definition I assume above you meant
extrinsic, right? We could also choose some other terms that are harder
to mix up…

Now for pseudo_super; it looks a bit weird, but I haven’t got any better
idea yet. I’m toying with something like this:

pdef foo(*args)
pre
a = something
# blah
post
print a
# blah2
end
end

It’s just that I want to get rid of the explicit call to super.

Your right. Sorry. But I do think sime of the same basic methods apply. Not
sure. I guess I need some examples to really be able to consider.

I think if we want to get AOP to Ruby, it won’t hurt to have examples
showing what it can do. For starters, we could search the AspectJ site for
examples and see what they look like in Ruby. But for the main dish we
probably need examples of our own to show the Full Potential. But I’m
looking at a busy week now, but after that I’ll have some time to give it
a serious try.

I think you’re right on. My implementation, instead, just adds more of the
same:

IMO, they both make sense. The existing version should use the
redefinition syntax, your new version the wrapping syntax, agreed?

Peter

Hi,

···

At Mon, 1 Dec 2003 23:10:44 +0900, T. Onoma wrote:

BTW does this mean if I redefine Array the literal form will use my new class?

class Array < MyArray
end

[1,2,3].kind_of?(MyArray) # => true

No. The interpreter current implementation uses rb_cArray
directly, and redefinition of built-in classes causes crash at
GC.


Nobu Nakada

wrap foo(*args)
# set a here, do other stuff not affecting the super call
result = psudeo_super
# use a here, do other stuff not affecting the result
end

Then we don’t need pre or post. I suppose if no “psuedo_super” is given
it would be assumed to be like a pre? I’m not sure. What do you think?

First a note: I think intrinsic and extrinsic got swapped between the
first mention of it and now. Maybe we should try to get these things
straight to avoid unnecessary misunderstandings. A wrap was intrinsic,
because it was an intrinsic part of the semantics of a method, and pre and
post were extrinsic because they were really just riding along quietly.
That sounds logical to me. By this definition I assume above you meant
extrinsic, right? We could also choose some other terms that are harder
to mix up…

Sorry, source of confusion: I used ‘wrap’ here to mean a combined pre and
post. (Mentally, I’m still repeating def for an intrinsic wraps). Perhaps
better terms are: inner wrap and outer wrap? So with the above I was pointing
out that we could just have a separate keyword for outer wrap definitions.

Now for pseudo_super; it looks a bit weird, but I haven’t got any better
idea yet. I’m toying with something like this:

pdef foo(*args)
pre
a = something
# blah
post
print a
# blah2
end
end

It’s just that I want to get rid of the explicit call to super.

You’re a man after my own heart! :slight_smile: I don’t know if you noticed the research
notes at the bottom of the RCR, but this is essentially one of the notations
I was playing with and very much liked. Perfect for outer wraps. And pdef
actually works pretty well too, once you think about it for a sec. Short and
to the point.

Your right. Sorry. But I do think sime of the same basic methods apply.
Not sure. I guess I need some examples to really be able to consider.

I think if we want to get AOP to Ruby, it won’t hurt to have examples
showing what it can do. For starters, we could search the AspectJ site for
examples and see what they look like in Ruby. But for the main dish we
probably need examples of our own to show the Full Potential. But I’m
looking at a busy week now, but after that I’ll have some time to give it
a serious try.

That would be great, I have some other work to do too. So afterward, I take it
you want to collaborate on a finalized joint RCR on the matter? That would be
excellent. And yes, some good examples are quite important.

I think you’re right on. My implementation, instead, just adds more of
the same:

IMO, they both make sense. The existing version should use the
redefinition syntax, your new version the wrapping syntax, agreed?

I think so. Could you clearify these two different syntaxes and where they
apply, so that I can be sure that I’m understanding you correctly?

-t0

···

On Monday 01 December 2003 12:25 am, Peter wrote:

I was thinking about the terms. To really distinguish these two types of wraps
for what they do I think the following terms, or similiar terms, would really
nail them down and prevent any confusion, and also help us think about them
better:

watch -or- monitor = extrinsic/outer wrap
submethod = intrinsic/inner wrap

Does this work for you?

Also I was wondering, how do we get the results of super with the following
code?

watch foo(*args)
pre
a = something
# blah
post
print a
# blah2
end
end

Note that I used watch instead of pdef just to see what it would look like. Of
course this notation also has the sticking point of what happens if pre and
post aren’t given (error?) and also how does super wrapping fit into this?

Also, in thinking about the purpose of a “watch wrap” it occurs to me that it
could still potentially effect the object (eg. @a = x) which I’m thinking
should probably be beyond its “write scope”. So perhaps it should be enclosed
in some sort of object-specifc read-only namespace? Kind of like Matz’
proposal:

http://www.rubyist.net/~matz/slides/rc2003/mgp00029.html

But applicable to methods. In other words a “watch” should have access to the
global namespace, but only read access to the local object’s namespace. So a
“watch wrap” is equivalent to a “submethod” using this kind of namespace
restriction:

(using my repeated definition syntax from the RCR)

def foo(*args)
namespace self
a = something
# blah
r = escape { super }
print a
# blah2
end
end

Where ‘namespace self’ means that any effects on the object self, made within
the namespace are “rolled back” at the end. But ‘escape’ means the namespace
doesn’t apply to what happens in its block.

This is a bit confusing, I know. Really just thinking out-loud here. I hope
the concepts I’m trying to convey make sense though.

-t0

···

On Monday 01 December 2003 12:25 am, Peter wrote:

First a note: I think intrinsic and extrinsic got swapped between the
first mention of it and now. Maybe we should try to get these things
straight to avoid unnecessary misunderstandings. A wrap was intrinsic,
because it was an intrinsic part of the semantics of a method, and pre and
post were extrinsic because they were really just riding along quietly.
That sounds logical to me. By this definition I assume above you meant
extrinsic, right? We could also choose some other terms that are harder
to mix up…

Hi,

···

At Tue, 2 Dec 2003 14:21:06 +0900, nobu.nokada@softhome.net wrote:

BTW does this mean if I redefine Array the literal form will use my new class?

class Array < MyArray
end

[1,2,3].kind_of?(MyArray) # => true

No. The interpreter current implementation uses rb_cArray
directly, and redefinition of built-in classes causes crash at
GC.

Sorry, built-ins are referred by class_tbl, so it won’t cause
crash even if you were redefine them.

We had a discussion about it once, but I forgot it and was
confused a bit.


Nobu Nakada