Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[ANN] [RCR] Cut-based AOP

5 views
Skip to first unread message

Trans

unread,
Oct 18, 2005, 7:56:16 PM10/18/05
to
This is to "officially" announce an RCR that I posted to RCR archive
two days ago. I realize the RCR itself is a bit dense and techincial,
so (with thanks to ES) I thought it might be a good idea to provide a
little summary and some examples of what it's all about and why it's a
such a good approach to AOP for Ruby.

You can read the RCR #321 <a
href="http://www.rcrchive.net/rcr/show/321">here</a>. To touch on it's
history: The RCR was developed by Peter Vanbroekhoven and myself over
the course of the last two years[1]. In that time we covered a lot of
territory with regards to AOP, and the RCR itself has undergone a great
deal of scrunity, revision and refinement.

To summaraize the RCR's senitment: The transparent subclass, witch we
have dubbed the Cut, is the best basis for adding AOP to Ruby because
it is fully harmonious with OOP. This is unlike other solutions which
are add-on abstractions tossed on top of the underlying OOP framework.
With cuts one has a building block to construct all sorts of AOP
systems, from simple method hooks to full blown context-oriented
programs. Put simply, the cut is a foundation for AOP, just as the
class is a foundation for OOP.

To demonstrate what you can do with cuts, I present a few simple
examples. I'll start with a very basci one: how to take a prexiting
class and wrap a user interface around it. Nothing fancy. I'll just use
a very small class and the console.

class Race

attr_accessor :distance, :speed, :track

def initialize( distance, speed )
@distance = distance
@speed = speed
@track = 0
end

def reset
@track = 0
end

def run
while track < distance do
self.track += 1;
sleep( 1.0/speed )
end
track
end

end

Simple enough. We can run a race:

Race.new( 10, 2 ).run

Though it goes about it's racey busniess just fine, we have no
indication of any progress of the race. But that's okay actually; it
keeps the Race class clean and focused on its core functionality.
Instead we can use a cut to watch the race.

cut Race::ConsoleViewer < Race
def track=(x)
r = super(x)
print "\e[0E"
print "+" * r
$stdout.flush
r
end
end

Race.new( 10, 2 ).run

This outputs an exra '+' at a time, finishing with 10:

++++++++++

So we see the progress of the race "live" without having to change the
Race class itself in any way. And we can just as easily throw any other
type of interface (gtk, qt, fox, wx, html, and so) around the Race
class in the same manner.

Now lets try a slightly more advance example; one made by Peter quite
some time ago, which demostrates the basis of how cuts could be used
for creating logging aspects. Lets say we have an ftp server class:

class FTPServer

def login(username, passwd)
# code for logging in, return ID for the connection
return connID
end

def logout(connID)
# code for logging out
end

def upload(connID, filename, data)
# code for writing a file
end

def download(connID, finename)
# code for reading a file, returns the data read
end

end

We can create an aspect for it:

module FTPLogging

def login(username, *args)
connID = super
log.print("#{connID}: #{username} logging in on #{Time.new}\n")
connID
end

def logout(connID)
result = super # In case logout returns some result
log.print("#{connID}: logging out on #{Time.new}\n")
result
end

def upload(connID, filename, *args)
result = super # In case logout returns some result
log.print("#{connID}: uploading #{filename} on #{Time.new}\n")
result
end

def download(connID, filename)
data = super
log.print("#{connID}: downloading #{filename} on #{Time.new}\n")
data
end

end

if logging_enabled
cut FTPLoggingCut < FTPServer
include FTPLogging
end
end

Notice the use of a separate module to house the aspect. That way it is
reusable. In this case the aspect's design was made to match the
duck-type of the target class, FTPServer, so we don't need to redirect
any advice in the cut. Though if we wanted to use the aspect on a class
not having the same interface we could easily redirect the advice on a
case by case basis. But even better, using an annotations system we
could create a routine to cut any class so annotated.

Finally, here's a example of how one might use cuts for dynamic
context-oriented programming.

class Account
attr_reader :id, :current
def initialize( id, current )
@id
@current = current
end
def debit( amount )
@current -= amount
end
def credit( amount )
@current -= amount
end
end

module Activiation
def active? ; @active ; end
def activate ; @active = true ; end
def deactivate ; @active = false ; end
end

cut AccountLogging < Account
extend Activation
def debit( amount )
r = super
if AccountLogging.active?
log "Debited account #{id} #{amount} with result #{r}"
end
r
end
end

cut AccountDatabase < Account
extend Activation
def debit( amount )
super
if AccountDatabase.active?
DB.transaction {
record_transaction( -amount )
record_total
}
end
end
def credit( amount )
super
if AccountDatabase.active?
DB.transaction {
record_transaction( amount )
record_total
}
end
end
def record_transaction( amount )
type = amount > 0 ? 'credit' : 'debit'
DB.exec "INSERT INTO transactions (account,#{type}) VALUES
(#{id},#{amount.abs});"
end
def record_total
DB.exec "UPDATE accounts SET total=#{current} WHERE id=#{id};"
end
end

Notice how we can activate and deactivate the aspects on the fly with
the activation module. If we wished we could go even further and create
a completely general purpose (and relatively efficient) context
switching mechinisms.

Oh, one more quick example taken from the RCR itself for those
wondering where the pointcut is, and how one might cross-cut a whole
slew of classes:

ObjectSpace.each_object(Class) { |c|
if c.instance_methods(false).include?(:to_s)
Cut.new(c) do
def :to_s
super.upcase + "!"
end
end
end
end
"a lot of shouting for joy".to_s #=> "A LOT OF SHOUTING FOR JOY!"

Okay, I think that should give a pretty good taste of what "AOP can do
for you" and how Cuts provide a solid, yet easy to use, foundation for
employing AOP on a wide scale. To understand more about why Cuts are
right for the task, covering all the criteria of AOP including
*introduction* and *inspection*, please give the RCR a read.

We hope you find our proposal rewarding and will show your supprt on
RCRchive.

Thanks,
T.


[1] I want to also thank Jamis Buck and everyone else who has spent
time exploring AOP for Ruby with us. Thank You!

dave...@gmail.com

unread,
Oct 18, 2005, 10:05:46 PM10/18/05
to
What is a cut? Is it a subclass that hides its parent's class? Are the
following two snippets the same?

cut Bar < Foo; baz() end

class Bar < Foo; baz() end
Bar = Foo # (except for this warning)

If not, what is the difference?

Cheers,
Dave

Christophe Grandsire

unread,
Oct 19, 2005, 5:47:56 AM10/19/05
to
Selon Trans <tran...@gmail.com>:

> This is to "officially" announce an RCR that I posted to RCR archive
> two days ago. I realize the RCR itself is a bit dense and techincial,
> so (with thanks to ES) I thought it might be a good idea to provide a
> little summary and some examples of what it's all about and why it's a
> such a good approach to AOP for Ruby.
>

I've just voted "strongly advocate" for it! After reading about AspectJ, I had
found that although aspects where interesting, they looked like they broke OOP
rather than enhanced it. This proposal, on the other hand, is strongly based on
OOP and really enhances it, and also makes AOP much easier to understand than
the traditional approach and its swarm of buzzwords. And it is nicely
unintrusive, ensuring that if one doesn't want to bother about AOP one doesn't
have to.

I just have a few questions, which I hope aren't too dumb ( ;) ). I couldn't
find anything in the RCR about those questions (although I may have missed it):
- will one be able to subclass (are rather "subcut", one would say) cuts?
- will cuts be as open as classes? (since they *are* classes, I'd expect so, but
I just want confirmation)
- how do cuts work with each other when you add more than one cut to the same
class?
- will the subclass of a class also inherit its superclass's cuts? This is a
tricky point I think, as one might expect that the functionality provided by
cuts should be available to subclasses, but the implementation (which is
basically like transparent subclasses) may forbid it. If they don't inherit
cuts, this could lead to surprises, with a not overriden method behaving
suddenly differently in the superclass and in the subclass. And what should one
expect of the behaviour of "super"?

All in all, I find it one of the best RCR I've ever read! Keep up the good work!
--
Christophe Grandsire.

http://rainbow.conlang.free.fr

It takes a straight mind to create a twisted conlang.


Peter Vanbroekhoven

unread,
Oct 19, 2005, 7:26:16 AM10/19/05
to
On Wed, 19 Oct 2005 dave...@gmail.com wrote:

> What is a cut? Is it a subclass that hides its parent's class? Are the
> following two snippets the same?
>
> cut Bar < Foo; baz() end
>
> class Bar < Foo; baz() end
> Bar = Foo # (except for this warning)

Did you mean the following? (Otherwise the class definition of Bar is
useless.)

Foo = Bar

> If not, what is the difference?

There are a few subtle differences:
* In the second snippet, Foo and Bar are the same. This means that code
that changes Foo changes Bar as well. In the first snippet, Bar is
invisible to someone using Foo. Changing Foo only changes Foo and leaves
Bar alone.
* In the second snippet, existing instances of class Foo are not affected,
while they are in the first case.

So the basic idea is the same, but a cut is designed to keep existing code
from breaking. It's supposed to be non-intrusive. That's what a cut does
and your second snippet does not.

Actually, in the beginning we considered something like your second code
snippet, but we decided it was not sufficient for our purposes as we
wanted to allow sneaking in a cut into an existing class hierarchy without
breaking the code that uses and changes these classes.

Peter


Peter Vanbroekhoven

unread,
Oct 19, 2005, 7:58:10 AM10/19/05
to
On Wed, 19 Oct 2005, Christophe Grandsire wrote:

> I've just voted "strongly advocate" for it! After reading about AspectJ, I had
> found that although aspects where interesting, they looked like they broke OOP
> rather than enhanced it. This proposal, on the other hand, is strongly based on
> OOP and really enhances it, and also makes AOP much easier to understand than
> the traditional approach and its swarm of buzzwords. And it is nicely
> unintrusive, ensuring that if one doesn't want to bother about AOP one doesn't
> have to.

Great! One down, many more to go ;-)

> I just have a few questions, which I hope aren't too dumb ( ;) ). I couldn't
> find anything in the RCR about those questions (although I may have missed it):
> - will one be able to subclass (are rather "subcut", one would say) cuts?

Cuts are not supposed to be subclassed (they can't be instantiated, so
what is the point?) We're not sure if we want to allow adding cuts to
cuts. I think the current implementation allows that, but I'm not sure,
it's been a while.

If you want to reuse the functionality of a cut somewhere else, you should
put it in a module and reuse it like that. In a way, allowing a cut to
apply to multiple classes or modules is akin to multiple-inheritance, and
we want to avoid that.

> - will cuts be as open as classes? (since they *are* classes, I'd expect so, but
> I just want confirmation)

Yes, they will be open wide.

> - how do cuts work with each other when you add more than one cut to the same
> class?

They stack on top of each other, the last one added being on top:

class A
def m ; '1' ; end
end

cut B < A
def m ; '[' + super + ']' ; end
end

cut C < A
def m ; '{' + super + '}' ; end
end

p A.new.m # => "{[1]}"

> - will the subclass of a class also inherit its superclass's cuts? This is a
> tricky point I think, as one might expect that the functionality provided by
> cuts should be available to subclasses, but the implementation (which is
> basically like transparent subclasses) may forbid it. If they don't inherit
> cuts, this could lead to surprises, with a not overriden method behaving
> suddenly differently in the superclass and in the subclass. And what should one
> expect of the behaviour of "super"?

Yes, subclasses inherit the cuts. This means that in the class hierarchy,
the cuts are in between the class and the superclass. To show this, some
example code:

class A
def m ; '1' ; end
end

class B < A
def m ; '{' + super + '}' ; end
end

cut C < A
def m ; '[' + super + ']' ; end
end

p A.new.m # => "[1]"
p B.new.m # => "{[1]}"

So the methods of a class are seen the same from the outside and from the
subclasses.

Note: if you use the patch, the keyword 'cut' is named '__cut__'. This is
because the Tk library uses 'cut' as a method name and it fails the tests
otherwise.

> All in all, I find it one of the best RCR I've ever read! Keep up the
> good work!

Thanks!

Peter


Christophe Grandsire

unread,
Oct 19, 2005, 8:58:54 AM10/19/05
to
Selon Peter Vanbroekhoven <calam...@gmail.com>:

>
> Great! One down, many more to go ;-)
>

LOL! Seriously, I really hope this RCR gets accepted. It is nicely
non-intrusive, and brings functionality that I'm sure many people would use if
it was there.

> > - will one be able to subclass (are rather "subcut", one would say) cuts?
>
> Cuts are not supposed to be subclassed (they can't be instantiated, so
> what is the point?)

I agree, which is why I corrected myself and said "subcut" afterwards :)

Dave Burt

unread,
Oct 19, 2005, 9:03:02 AM10/19/05
to
Peter Vanbroekhoven explained:

> On Wed, 19 Oct 2005 dave...@gmail.com wrote:
>
> Did you mean the following? (Otherwise the class definition of Bar is
> useless.)
>
> Foo = Bar

Quite. Let's imagine that's what I said.

> There are a few subtle differences:
> * In the second snippet, Foo and Bar are the same. This means that code
> that changes Foo changes Bar as well. In the first snippet, Bar is
> invisible to someone using Foo. Changing Foo only changes Foo and leaves
> Bar alone.
> * In the second snippet, existing instances of class Foo are not affected,
> while they are in the first case.
>
> So the basic idea is the same, but a cut is designed to keep existing code
> from breaking. It's supposed to be non-intrusive. That's what a cut does
> and your second snippet does not.
>
> Actually, in the beginning we considered something like your second code
> snippet, but we decided it was not sufficient for our purposes as we
> wanted to allow sneaking in a cut into an existing class hierarchy without
> breaking the code that uses and changes these classes.

OK, great. I'm starting to see the usefulness of this. It occurs to me that
there is some similarity between this and selector namespaces (targeted for
Ruby 2) -- a lot of what I imagined namespaces being useful for (i.e. making
changes to a core class that only affects code within a particular limited
context) is accomplished easily using cuts.

I still don't know anything, really, about Ruby namespaces. Something else
to look forward too, and something complementary to this, I guess.

Last thing, a criticism: shouldn't cut be a module, but not a class, because
classes are instantiable?

Cheers,
Dave


Peter Vanbroekhoven

unread,
Oct 19, 2005, 9:50:10 AM10/19/05
to
On Wed, 19 Oct 2005, Dave Burt wrote:

> Peter Vanbroekhoven explained:
>> On Wed, 19 Oct 2005 dave...@gmail.com wrote:
>>
>> Did you mean the following? (Otherwise the class definition of Bar is
>> useless.)
>>
>> Foo = Bar
>
> Quite. Let's imagine that's what I said.

Done :-)

> OK, great. I'm starting to see the usefulness of this. It occurs to me that
> there is some similarity between this and selector namespaces (targeted for
> Ruby 2) -- a lot of what I imagined namespaces being useful for (i.e. making
> changes to a core class that only affects code within a particular limited
> context) is accomplished easily using cuts.

There are definitely parallels, but cuts are at this moment not
context-aware by themselves. Something like namespaces can be done as
follows:

cut FileLogging < File
def initialize(*args, &blk)
do_some_logging if Thread.current[:LOGGING_ENABLED]
super
do_some_more_logging if Thread.current[:LOGGING_ENABLED]
end
end

def with_logging
old_logging = Thread.current[:LOGGING_ENABLED]
Thread.current[:LOGGING_ENABLED] = true
yield
Thread.current[:LOGGING_ENABLED] = old_logging
end

f1 = File.new('some_file') # => no logging
with_logging do
f2 = File.new('some_other_file') # => with logging
end

I think though that this is different from selector namespaces, as my
example provides different behavior in a dynamic scope, and selector
namespaces are about static scope. That's provided I understand about
selector namespaces myself.

> I still don't know anything, really, about Ruby namespaces. Something else
> to look forward too, and something complementary to this, I guess.
>
> Last thing, a criticism: shouldn't cut be a module, but not a class, because
> classes are instantiable?

First things first: when you talk about cut, is that Cut, or an instance
of Cut? If it's the latter, then the answer is that we had long
discussions about whether Cut should be a subclass of Class or of Module.
There are some features that make it class, and some features that make it
a module:

* a module because:
- Not instantiable (though singleton classes aren't instatiable either)
* a class because
- Not includable (though neither is Class which is a subclass of Module
too)
- It has a superclass, namely the class it cuts

So you see, there are arguments for both, and in the end we settled on it
being a class.

Peter


Eric Mahurin

unread,
Oct 19, 2005, 10:23:08 AM10/19/05
to
What's the reason for naming the cut? In all of the code I've
seen so far, the actual cut is never used. So instead of:

cut C < A ... end

why not:

cut < A ... end

or:

cut A ... end

The only thing I can think of off hand is that you might want
to remove the cut down the road.

Conceptually, I think it is easier to think of this cut
operating on the parent class (make it look like you're just
reopening the class). You could think of this "cut" as
something just like "class" except that the superclass is
treated as the previous definition of "class". This also would
extend well to making a cut on the meta class of an object:

cut <<obj ... end

From the syntax you proposed, it would be something like this I
believe:

cut A < <<obj ... end

I didn't see anything in the proposal about cutting the
meta-class of an object, but the above seems like what the
syntax would be. Naming the cut just seems unnecessarily
verbose and complicates the concept.

Here are 2 other ideas that accomplish the majority of what you
are talking about without being so grandiose:

- have another type of def/#define_method (maybe
redef/#redefine_method) that allows redefinition of a method
such that "super" is treated as the previous definition.

- have another keyword like "super" that means previous
definition.

Right now you can actually manually do something like the
above:

class C
def foo;"foo";end
end

c = C.new

c.foo # => "foo"

class C
foo1 = instance_method(:foo)
define_method(:foo) { "{"+foo1.bind(self).call+"}" }
end

c.foo # => "{foo}"

class C
foo1 = instance_method(:foo)
define_method(:foo) { "["+foo1.bind(self).call+"]" }
end

c.foo # => "[{foo}]"

Pretty sweet, huh? I wasn't sure if foo1 kept the previous
definition until I tried it, but apparently it does.

Maybe just an easier way to do the above is all that is needed.
I think the above covers what is really needed for AOP - and
we already have it. Just simpler syntax is needed IMO. No
extra baggage needs to be added to the class data structures.

I'm not sure why you guys made such a lengthy RCR. I think I
have the concept now, but with all of the verbosity, it makes
it difficult to figure out what you are really proposing. I
think a much more concise RCR would have been better.



__________________________________
Yahoo! Music Unlimited
Access over 1 million songs. Try it free.
http://music.yahoo.com/unlimited/


Dave Burt

unread,
Oct 19, 2005, 10:24:48 AM10/19/05
to
Peter Vanbroekhoven:

> First things first: when you talk about cut, is that Cut, or an instance
> of Cut?

Yes. We're talking about the Cut in the inheritance heirarchy.

(I don't see the ambiguity; I'd read "a cut is a module" as "an instance of
Cut is also an instance of Module", which implies "Cut < Module".)

> If it's the latter, then the answer is that we had long discussions about
> whether Cut should be a subclass of Class or of Module. There are some
> features that make it class, and some features that make it a module:
>
> * a module because:
> - Not instantiable (though singleton classes aren't instatiable either)
> * a class because
> - Not includable (though neither is Class which is a subclass of Module
> too)
> - It has a superclass, namely the class it cuts
>
> So you see, there are arguments for both, and in the end we settled on it
> being a class.

I don't see the balance falling the same way -- I see Cut much happier as a
peer to Class than a subclass of it.
- My main reason is that a subclass of Class should be instantiable; that's
the primary difference between Class and Module.
- That singleton classes aren't instantiable is an interesting point, but
those are kind of obscure, whereas a cut is not, with an added keyword and
all.
- Cut#superclass and Class#superclass are different, as it's a different
kind of relationship.
- include and extend only accept objects whose class is Module, so this is a
non-issue

Can you un-settle on it being a class?

Cheers,
Dave


Jeff Wood

unread,
Oct 19, 2005, 10:34:07 AM10/19/05
to
Although I see the power of the examples and the ideas, it seems like
it's a bit watered down compared to AspectJ or other Aspect
frameworks.

Usually, the definition of cuts allow you to wrap many things at once...

AspectJ ( for instance ) allows you to use wildcards in both the
object type and the method names that are getting wrapped. It allows
you to add general functionality ( like debugging logs or security
control ) very easily to chunks ( of any size, even all ) of your
application.

I'd like to see something like that for Ruby, but I do think that your
idea is a good start.

maybe something that allows cut to take some wildcards

Cut.new( "FileLogging" ) do

wrap_method( File, :any ) do |method, *args|
# do logging stuff
method.call( *args )
# do more logging stuff
end

end

or instead of File ...simply

wrap_method( IO, :any ) ...
...
end

which would turn around and add this cut to any object of that type (
or a derivative ) of IO

Anyways, just additional thoughts. Shouldn't be too hard to implement
as objects now within Ruby as it exists...

The only trick is catching overrides and new types that are defined
AFTER the cut has been added.

.. just my $0.02US

j.


--
"http://ruby-lang.org -- do you ruby?"

Jeff Wood


Peter Vanbroekhoven

unread,
Oct 19, 2005, 11:09:16 AM10/19/05
to
On Wed, 19 Oct 2005, Eric Mahurin wrote:

> What's the reason for naming the cut? In all of the code I've
> seen so far, the actual cut is never used. So instead of:
>
> cut C < A ... end
>
> why not:
>
> cut < A ... end
>
> or:
>
> cut A ... end
>
> The only thing I can think of off hand is that you might want
> to remove the cut down the road.

Well, naming the cut is interesting if you want to reopen the cut and
change some methods. And in general for managing the cuts, like removing.

Just like with classes, if you don't want to store the cut or don't want
to waste a constant on it, use the constructor:

Cut.new(A) do ... end

> Conceptually, I think it is easier to think of this cut
> operating on the parent class (make it look like you're just
> reopening the class). You could think of this "cut" as
> something just like "class" except that the superclass is
> treated as the previous definition of "class". This also would
> extend well to making a cut on the meta class of an object:
>
> cut <<obj ... end

Sure, and this is exactly how you can do it.

>> From the syntax you proposed, it would be something like this I
> believe:
>
> cut A < <<obj ... end

What makes you say so? Given that subclassing is done like "class A < B"
it does not mean that opening the singleton class of B look like "class A
< << B". Some here. If you want to give the cut a name, use "cut A < B",
if you want to cut the metaclass, use "cut << B", and if you want an
anonymous cut, use "Cut.new(A)".

> I didn't see anything in the proposal about cutting the
> meta-class of an object, but the above seems like what the
> syntax would be. Naming the cut just seems unnecessarily
> verbose and complicates the concept.

Then it must be missing from the proposal, it was certainly intended to be
possible. As for the unnecessary complexity, I don't agree. Naming the cut
allows you to access it again, and change methods ro remove them, etc. It
gives you a handle on them.

> Here are 2 other ideas that accomplish the majority of what you
> are talking about without being so grandiose:
>
> - have another type of def/#define_method (maybe
> redef/#redefine_method) that allows redefinition of a method
> such that "super" is treated as the previous definition.

In a way this is what Matz wanted to do with "def method:wrap", it's just
a different syntax. A big problem with this is how to manage these
redefinitions. How do you propose we redefine or remove a specific
rededinition if there are many for the same method?

> - have another keyword like "super" that means previous
> definition.

We've been over that in our discussions before. One problem is that that
keyword can be hidden inside an eval and all, which makes it impossible to
determine whether the previous definition is actually called. This causes
a problem with garbage collecting previous method definitions, as it is
impossible to determine the dead ones automatically in all possible cases.

Also, this does still not allow the redefinitions to be managed in any
sensible way.

The reason for cuts, for naming them, and the rest of the RCR, is simply
because any other way proposed (using closures as above, and already shown
in the past by Ara I think, or using method aliasing, and so on) makes it
very hard to manage the stack of methods. Cuts give you the handle to do
so. If you want the set of methods you've added, you can just grab the cut
and you've got them.

We've been over all these things before in our discussions, including what
you mention above, and none of it works well with Ruby's dynamic nature.
Because cuts are based in inheritance, it does work with Ruby's dynamic
nature.

Peter


Christophe Grandsire

unread,
Oct 19, 2005, 11:24:11 AM10/19/05
to
Selon Peter Vanbroekhoven <calam...@gmail.com>:

>
> Then it must be missing from the proposal, it was certainly intended to be
> possible.

It isn't. Both "Cut.new(A) {...}" and "cut <<obj ... end" are shown in the text
of the RCR. You didn't forget them. Eric just overlooked them.

As for the unnecessary complexity, I don't agree. Naming the cut
> allows you to access it again, and change methods ro remove them, etc. It
> gives you a handle on them.
>

It also allows you to define more than one cut on one class, allowing you to
organise the concerns by domain and meaning, instead of having one big mess of
concerns in a single place (or worse: in the original class).

As for the RCR being not concise enough, I found it to be just right. Aspects
are usually described with undefined buzzwords and a lot of propaganda. It was
nice to see something more palatable, which took the time to explain clearly
and in a neutral tone the ins and outs of cuts and AOP.


>
> The reason for cuts, for naming them, and the rest of the RCR, is simply
> because any other way proposed (using closures as above, and already shown
> in the past by Ara I think, or using method aliasing, and so on) makes it
> very hard to manage the stack of methods. Cuts give you the handle to do
> so. If you want the set of methods you've added, you can just grab the cut
> and you've got them.
>

And if you want only the methods related to one particular concern, just grab
the cut you specifically defined for it, and don't touch the others. I also
think it would make AOP easier to document in the source code.

Peter Vanbroekhoven

unread,
Oct 19, 2005, 11:30:11 AM10/19/05
to

> ... just my $0.02US

Thanks for contribution ;-)

Well, I think we are aware of this. Cuts provide the basis of AOP, namely
the basic wrapping functionality, and providing a convenient handle to the
wrapping methods. These things can then be used in a full-fledged AOP
library that provides wildcards and all. But I think the important point
is that we think that cuts are a good basis for AOP. Anything on top of
that is sugar. And because cuts fit well within Ruby's OO system, it will
be good sugar!

Peter


Trans

unread,
Oct 19, 2005, 11:45:38 AM10/19/05
to
Jeff Wood wrote:
> Although I see the power of the examples and the ideas, it seems like
> it's a bit watered down compared to AspectJ or other Aspect
> frameworks.

As the RCR points out, this is purposeful and with good reason. We've
designed a foundation. Ruby has plenty of capabilites for doing these
other "watered up" things. The problem with these other frameworks is
that you are always forced to do the "watered up" thing, but more often
teh usecases don't warrant it.

> Usually, the definition of cuts allow you to wrap many things at once...

You mean *cross-cut*. We draw a distinction. In fact, I'm not sure if I
have ever seen anyone else use the term "cut" withuout "cross". It is a
distinction that may be original.

> AspectJ ( for instance ) allows you to use wildcards in both the
> object type and the method names that are getting wrapped. It allows
> you to add general functionality ( like debugging logs or security
> control ) very easily to chunks ( of any size, even all ) of your
> application.

We've explored this extensively. Cutting based on method names is very
*bad*. And while wildcard cutting seems great, you'll find that adding
aspects to *all* or even *most* of your app is rearely desirable.
Typically, it is very specific classes and specific methods within them
that need advising. The exceptions are for meta-programming needs like
unit-testing and debugging. But as I say, these are exceptional. (It is
rather ironic perhaps, but many people do not even think of AOP as
being applicable to anything but these "meta" usecases b/c of the way
current AOP frameworks work!)

> I'd like to see something like that for Ruby, but I do think that your
> idea is a good start.
>
> maybe something that allows cut to take some wildcards
>
> Cut.new( "FileLogging" ) do
>
> wrap_method( File, :any ) do |method, *args|
> # do logging stuff
> method.call( *args )
> # do more logging stuff
> end
>
> end

This can be done with the RCR as proposed, along the lines of:

cut FileLogging < File

redirect_advice instance_methods => :log

def log( target )
# do logging stuff
target.super


# do more logging stuff
end

end

> or instead of File ...simply
>
> wrap_method( IO, :any ) ...
> ...
> end
>
> which would turn around and add this cut to any object of that type (
> or a derivative ) of IO

Your example would have to be expanded on, it's not explicit enough.
Nonetheleass you can do such things in similar fashion to the above
example.

> Anyways, just additional thoughts. Shouldn't be too hard to implement
> as objects now within Ruby as it exists...

Right!

> The only trick is catching overrides and new types that are defined
> AFTER the cut has been added.

Indeed, that requires some extra code in a #method_added hook. And
certainly it would be possible to write some methods that did that
automatically too. Cuts can advise #method_added hook too ;)

I think the important thing to understand is how Cut is a foundation
for AOP. Going the direction of Aspect/J and the like, IMO, are like
building a house from the roof down.

T.

Peter Vanbroekhoven

unread,
Oct 19, 2005, 11:46:13 AM10/19/05
to
On Wed, 19 Oct 2005, Christophe Grandsire wrote:

> I find it a great idea to use modules for cuts to. A genial way to minimise the
> amount of new features to implement and learn!

Thank you for the kind words!

> So I don't have to worry that subclasses would suddenly behave differently from
> their parents without explicit overriding. Cool.
>
> That said, I'm suddenly thinking that sometimes one would rather want to
> subclass the class as it stands without its aspects. If I'm thinking for
> instance of the issue of logging. The way it stands now, if the parent class
> gets a logger cut, the subclass suddenly gets logging functionality *in the
> middle of its overridden methods*, when they use super, whereas one would
> rather expect the logging aspect to be *external* to the implementation of the
> subclass (if it is to be there at all). I hope I'm making myself clear. I have
> difficulties to express my thoughts in words today...

I think I know what you mean. I think this can be done with a bit of
library support. The following should do what you want it to do, and it
can surely be done automatically by a library:

class A
def do_transaction ; ... ; end
end

class B < A
def do_transaction
do_some_stuff
super
end
end

module CutMixin
def do_transaction
do_logging if Thread.current['InsideLogger']
old = Thread.current['ACut::InsideLogger']
Thread.current['ACut::InsideLogger'] = true
super
Thread.current['ACut::InsideLogger'] = old
do_logging if Thread.current['InsideLogger']
end
end

cut ACut < A
include ACutMixin
end

cut BCut< B
include ACutMixin
end

> What do you think? I like the way cuts act in a really transparent way, and that
> when subclassing one needn't know about the existence of cuts, but I'm now
> wondering whether it could be a problem in some cases when the aspect should
> really stay external to the implementation of classes... Do you have a way to
> solve that problem already?


>
>> Note: if you use the patch, the keyword 'cut' is named '__cut__'. This is
>> because the Tk library uses 'cut' as a method name and it fails the tests
>> otherwise.
>>
>

> I hope this small problem won't prevent the RCR to be accepted.


> --
> Christophe Grandsire.
>
> http://rainbow.conlang.free.fr
>
> It takes a straight mind to create a twisted conlang.

Peter


Jeff Wood

unread,
Oct 19, 2005, 11:54:08 AM10/19/05
to
Thank you for the clarification.

j.

Peter Vanbroekhoven

unread,
Oct 19, 2005, 12:15:11 PM10/19/05
to
On Wed, 19 Oct 2005, Dave Burt wrote:

> Peter Vanbroekhoven:
>> First things first: when you talk about cut, is that Cut, or an instance
>> of Cut?
>
> Yes. We're talking about the Cut in the inheritance heirarchy.
>
> (I don't see the ambiguity; I'd read "a cut is a module" as "an instance of
> Cut is also an instance of Module", which implies "Cut < Module".)

Ah, I see. But you asked "shouldn't cut be a module". There's no "a"
before the "cut", which causes the ambiguity. I just asked to make sure I
wasn't misinterpreting. I do that when there are these tiny ambiguities in
a sentence.

>> If it's the latter, then the answer is that we had long discussions about
>> whether Cut should be a subclass of Class or of Module. There are some
>> features that make it class, and some features that make it a module:
>>
>> * a module because:
>> - Not instantiable (though singleton classes aren't instatiable either)
>> * a class because
>> - Not includable (though neither is Class which is a subclass of Module
>> too)
>> - It has a superclass, namely the class it cuts
>>
>> So you see, there are arguments for both, and in the end we settled on it
>> being a class.
>
> I don't see the balance falling the same way -- I see Cut much happier as a
> peer to Class than a subclass of it.
> - My main reason is that a subclass of Class should be instantiable; that's
> the primary difference between Class and Module.
> - That singleton classes aren't instantiable is an interesting point, but
> those are kind of obscure, whereas a cut is not, with an added keyword and
> all.
> - Cut#superclass and Class#superclass are different, as it's a different
> kind of relationship.
> - include and extend only accept objects whose class is Module, so this is a
> non-issue
>
> Can you un-settle on it being a class?

Sure. We've never managed a final decision on this, and because
implementation-wise both are possible, we settled on one of them to
prevent us from getting stuck arguing over a detail that is easy enough to
change. Problem is that most arguments for or against making cuts modules
are not conclusive or at least partly subjective. You make a pretty good
case though.

Peter


Trans

unread,
Oct 19, 2005, 12:38:08 PM10/19/05
to

Eric Mahurin wrote:
> Right now you can actually manually do something like the
> above:
>
> class C
> def foo;"foo";end
> end
>
> c = C.new
>
> c.foo # => "foo"
>
> class C
> foo1 = instance_method(:foo)
> define_method(:foo) { "{"+foo1.bind(self).call+"}" }
> end
>
> c.foo # => "{foo}"
>
> class C
> foo1 = instance_method(:foo)
> define_method(:foo) { "["+foo1.bind(self).call+"]" }
> end
>
> c.foo # => "[{foo}]"
>
> Pretty sweet, huh? I wasn't sure if foo1 kept the previous
> definition until I tried it, but apparently it does.
>
> Maybe just an easier way to do the above is all that is needed.
> I think the above covers what is really needed for AOP - and
> we already have it. Just simpler syntax is needed IMO. No
> extra baggage needs to be added to the class data structures.

Peter covers this well in his repsonse. I just want to point out one
additional thing about using a Cut rather using simple method hooks:
*introduction*. Using Cuts will allow you to conveniently store
information (i.e. state) pertaining to that cut/aspect independent of
the class being cut --an important criterea for good AOP. Presently
class instance vars are what you'd use for this, but as Ruby comes to
support local instance varaibles and/or methods introduction will
become even better.

> I'm not sure why you guys made such a lengthy RCR. I think I
> have the concept now, but with all of the verbosity, it makes
> it difficult to figure out what you are really proposing. I
> think a much more concise RCR would have been better.

Granted there are some spots where we could have been a little more
concise. But we wanted to be thurough, much like a white paper, rather
then something just thought up of a few days ago and thrown up. We also
hope the brief overwiew of AOP would be of benefit to those not so
familar with AOP.

Thanks,
T.

Dave Burt

unread,
Oct 19, 2005, 9:17:51 PM10/19/05
to
Peter Vanbroekhoven:

> Ah, I see. But you asked "shouldn't cut be a module". There's no "a"
> before the "cut", which causes the ambiguity. I just asked to make sure I
> wasn't misinterpreting. I do that when there are these tiny ambiguities in
> a sentence.

Ah, yes. I'm not doing too well with accuracy in this thread, am I?

>> I don't see the balance falling the same way -- I see Cut much happier as
>> a
>> peer to Class than a subclass of it.
>> - My main reason is that a subclass of Class should be instantiable;
>> that's
>> the primary difference between Class and Module.
>> - That singleton classes aren't instantiable is an interesting point, but
>> those are kind of obscure, whereas a cut is not, with an added keyword
>> and
>> all.
>> - Cut#superclass and Class#superclass are different, as it's a different
>> kind of relationship.
>> - include and extend only accept objects whose class is Module, so this
>> is a
>> non-issue
>>
>> Can you un-settle on it being a class?
>
> Sure. We've never managed a final decision on this, and because
> implementation-wise both are possible, we settled on one of them to
> prevent us from getting stuck arguing over a detail that is easy enough to
> change. Problem is that most arguments for or against making cuts modules
> are not conclusive or at least partly subjective. You make a pretty good
> case though.

Thanks. I do feel pretty strongly about my first point (classes are
instantiable) and I think it really comes down to that on the Module side
versus cuts being part of the class inheritance heirarchy on the other. And
the nature of cut inheritance does separate it from the class heirarchy.

Cheers,
Dave


Trans

unread,
Oct 19, 2005, 10:13:02 PM10/19/05
to
|Thanks. I do feel pretty strongly about my first point (classes are
|instantiable) and I think it really comes down to that on the Module
side
|versus cuts being part of the class inheritance heirarchy on the
other. And
|the nature of cut inheritance does separate it from the class
heirarchy.

On the other hand cuts are in essence classes --transparent
*subclasses* to be exact. While you do not instantiate them directly,
they get instantiated as part of the class they cut.

I think the real incongruency comes more from the fact that Class
itself is a subclass of Module. It works okay, but conceptualy it is
odd. And on occasion you have undef a method in Class that's been
defined in Module. I think Matz even metions something liek this in his
recent presentation. It think a better solution would come from having
a "ClassKernel" module which is included in Module and Class, so they
can stand on their own.

Finally, I think cuts are simliar to singleton_classes in that
instantiating them is restricted.

o = Object.new
=> #<Object:0xb7aa96a0>
irb(main):002:0> eigenclass = class << o; self ; end
=> #<Class:#<Object:0xb7aa96a0>>
irb(main):003:0> k = eigenclass.new
TypeError: can't create instance of virtual class
from (irb):3:in `new'
from (irb):3

But I don't think there's any techincal reason they could not be. It's
purposefully disallowed, I guess for conceptual reasons:

VALUE
rb_class_new(super)
VALUE super;
{
Check_Type(super, T_CLASS);
if (super == rb_cClass) {
rb_raise(rb_eTypeError, "can't make subclass of Class");
}
if (FL_TEST(super, FL_SINGLETON)) {
rb_raise(rb_eTypeError, "can't make subclass of virtual class");
}
return rb_class_boot(super);
}

Hey, this still says "virtual class"; _why doesn't his say eigenclass!?
;)

T.

itsm...@hotmail.com

unread,
Oct 19, 2005, 11:48:47 PM10/19/05
to

Trans wrote:
> This is to "officially" announce an RCR that I posted to RCR archive
> two days ago. I realize the RCR itself is a bit dense and techincial,
> so (with thanks to ES) I thought it might be a good idea to provide a
> little summary and some examples of what it's all about and why it's a
> such a good approach to AOP for Ruby.
>
> You can read the RCR #321 <a
> href="http://www.rcrchive.net/rcr/show/321">here</a>.

+1.

I have a few questions I'll need to frame properly, but wanted to say:
Nice work + nice description!

Yukihiro Matsumoto

unread,
Oct 20, 2005, 1:37:17 AM10/20/05
to
Hi,

In message "Re: [ANN] [RCR] Cut-based AOP"


on Wed, 19 Oct 2005 08:56:59 +0900, "Trans" <tran...@gmail.com> writes:

|This is to "officially" announce an RCR that I posted to RCR archive
|two days ago. I realize the RCR itself is a bit dense and techincial,
|so (with thanks to ES) I thought it might be a good idea to provide a
|little summary and some examples of what it's all about and why it's a
|such a good approach to AOP for Ruby.

I understand the basic idea. How about introducing a new method
e.g. "preclude" that works to intercept the methods in the target
class/module, instead of cut. It would be a counterpart of "include"
for mix-in.

matz.


Sean O'Halpin

unread,
Oct 20, 2005, 5:10:55 AM10/20/05
to
On 10/20/05, Yukihiro Matsumoto <ma...@ruby-lang.org> wrote:
> How about introducing a new method
> e.g. "preclude" that works to intercept the methods in the target
> class/module, instead of cut. It would be a counterpart of "include"
> for mix-in.

I like the idea but may I point out that "preclude" has a meaning very
close to "exclude". How about "intercept"?

Regards,

Sean


Alexandru Popescu

unread,
Oct 20, 2005, 6:11:07 AM10/20/05
to
Hi!

I would like to comment on this proposal. I can agree right from the beginning that the points here
will be presented from a not-so-rubiesc perspective.

the proposal looks like an method-interception framework, rather than a full blown aop solution.

The proposal is mixin together theoretical aspects of aop with Ruby specific implementation
problems. While this cannot be considered a real problem, what I have noticed is that one of the
main concepts of the AOP pointcuts are completely ignored.

The main idea behind AOP is to be able to define crosscutting concerns. This looks pieces of
functionality that can be used disregarding the OO nature of the project.

While at the first glance the method interception mechanism is one of most important aspects of AOP,
there are a few distinction that must be considered: call vs execution, before, around, after pieces
of advice.

While, maybe leaving alone all these aspects, may be a Ruby implementation constraint, they are
valid AOP principles that will miss from the implementation.

cheers,

/alex
--
w( the_mindstorm )p.

#: Trans changed the world a bit at a time by saying on 10/19/2005 1:56 AM :#

nobuyoshi nakada

unread,
Oct 20, 2005, 6:29:38 AM10/20/05
to
Hi,

At Thu, 20 Oct 2005 18:10:55 +0900,
Sean O'Halpin wrote in [ruby-talk:161614]:


> > How about introducing a new method
> > e.g. "preclude" that works to intercept the methods in the target
> > class/module, instead of cut. It would be a counterpart of "include"
> > for mix-in.
>
> I like the idea but may I point out that "preclude" has a meaning very
> close to "exclude". How about "intercept"?

The method lookup order feels "post"clude rather than
"pre"clude. ;)

--
Nobu Nakada


tad.b...@bnpparibas.com

unread,
Oct 20, 2005, 6:53:14 AM10/20/05
to
Hi ... need help ...

Just had Ruby 1.8.3 installed on our HP-UX box, and it seems to be
really misbehaving... I'm trying to promote Ruby here but this is
giving it bad press.

For example, the following code

#!/usr/local/bin/ruby
p ARGV
ARGV.each do |fname |
puts "File: #{fname}"
loop do
break
end
end

gives .....

> xdump param
["param"]
File: param
/home/fcux_dev/tadb/bin/xdump:6: [BUG] Bus Error
ruby 1.8.3 (2005-09-21) [hppa2.0w-hpux11.11]
Abort(coredump)
>
And in fact, this error ([BUG] Bus Error - what is it ?) seems to pop up
at the slightest provocation, although some relatively complex
ruby code seems to run ok.
I didn't do the installation myself, but I suspect that the HP-UX
bundled C compiler was used to do the installation.
Could that be the problem ?

This message and any attachments (the "message") is
intended solely for the addressees and is confidential.
If you receive this message in error, please delete it and
immediately notify the sender. Any use not in accord with
its purpose, any dissemination or disclosure, either whole
or partial, is prohibited except formal approval. The internet
can not guarantee the integrity of this message.
BNP PARIBAS (and its subsidiaries) shall (will) not
therefore be liable for the message if modified.

---------------------------------------------

Ce message et toutes les pieces jointes (ci-apres le
"message") sont etablis a l'intention exclusive de ses
destinataires et sont confidentiels. Si vous recevez ce
message par erreur, merci de le detruire et d'en avertir
immediatement l'expediteur. Toute utilisation de ce
message non conforme a sa destination, toute diffusion
ou toute publication, totale ou partielle, est interdite, sauf
autorisation expresse. L'internet ne permettant pas
d'assurer l'integrite de ce message, BNP PARIBAS (et ses
filiales) decline(nt) toute responsabilite au titre de ce
message, dans l'hypothese ou il aurait ete modifie.

Peter Vanbroekhoven

unread,
Oct 20, 2005, 8:01:24 AM10/20/05
to

Hi Matz,

This is indeed an option we have considered, and not completely dismissed
either. Trans just asked me yesterday whether I could add this on top of
cuts. I think part of the reason that we came up with cuts was because it
is more like subclassing. One argument that I remember is that a class
creates a wrapper around its superclass, and can actually adapt to its
superclass. However, a mix-in cannot adapt to the class it is included in,
because it can be included in many classes and it can't cater to all their
needs. Likewise a superclass cannot adapt to its subclasses. Because the
idea of a wrapper adapting itself to the class it wraps is appealing, but
can only be done if it can wrap only a single class. Hence the idea of a
cut, and not just module 'preclusion'. I don't know what your thoughts are
on this.

Does this mean you like the general idea, of just slipping a module or
class into the class hierarchy and put the wrapper methods there? This
could possibly be used with the :before and :after syntax you've proposed,
with a little extension that allows naming the layer it should go to:

class Foo
def foo
p :foo
end
end

class Bar < Foo
def foo:wrap:Layer
p [:foot, :before]
super
p [:foot, :after]
end
end

All these methods could end up in an (autovivified?) 'precluded' module,
overwrite only methods in that module, and this module can be retrieved
for more fun.

This is just an idea that was floating around in my mind. The syntax (in
case you don't like it) is not the point though, the idea is.

Peter


Christophe Grandsire

unread,
Oct 20, 2005, 8:20:36 AM10/20/05
to
Selon Alexandru Popescu <the.mindstor...@gmail.com>:

>
> While, maybe leaving alone all these aspects, may be a Ruby implementation
> constraint, they are
> valid AOP principles that will miss from the implementation.
>

From the rest of the discussion here about this RCR, I have understood (and
Trans or others can confirm it I think) that cuts are supposed to be a *basis*,
on which fully-fledged AOP can be built, in a way that fits with Ruby, since the
base itself fits with Ruby. It's a bottom-up approach, instead of the top-down
approach that for instance AspectJ took, and which makes it look very alien to
the rest of Java (in my opinion). I personally believe it's the best approach,
which is why I voted for this RCR: first built the tools you need, then use
those tools to create a framework. This is in my opinion the only way to get
something eventually stable and useful, without looking too much like an add-on
but really like part of the language.

In other words, the RCR isn't here to propose full AOP in one go. It is there to
provide what the authors think (and so far I agree) is the only construct
missing to built fully-fledged AOP, in a way that doesn't break with the rest
of Ruby, and is easy enough to implement. I guess (but never having used it I
might be wrong) that full AOP could be built then as a standard library, built
on cuts and ObjectSpace, and/or Ruby's already existing reflection capacities.

I am always in favour op bottom-up approaches. They may sometimes seem slower,
but on the long term they result in better code, especially when each tool and
addition is built as independently as possible. In a top-down approach, people
seem often far too tempted to look at their project as a single whole, and thus
to build it in such a way, resulting in code which after some time gets
unmanageable.

I am really in favour of cuts (or maybe some other way to implement the same
concept, using modules like matz suggested), because they provide a strong,
stable foundation, on which not only AOP can be built, but who knows what more?
Cuts extend the notion of modularity in a way different from simple modules, and
this could very well lead to plenty of other things besides AOP which is the
main issue they were built for. In other words, don't get too blinded by the
issue of fully-fledged AOP when you review this RCR. See it as foundation for
it, and maybe quite a few other things.

Eric Mahurin

unread,
Oct 20, 2005, 10:00:43 AM10/20/05
to

+1, if it is what I think you mean. Is this what you mean?

class C
def foo
"bar"
end
end

c = C.new
c.foo # => "bar"

module Braces
def foo
"{"+super+"}"
end
end

class C
preclude Braces
end

c.foo # => "{bar}"

module Brackets
def foo
"["+super+"]"
end
end

class C
preclude Brackets
end

c.foo # => "[{bar}]"

module Braces
remove_method :foo
end

c.foo # => "[bar]"

I really like this. I don't see anything you couldn't do with
this that you can with the cut-based-AOP. And it seems so much
simpler.




__________________________________
Yahoo! Mail - PC Magazine Editors' Choice 2005
http://mail.yahoo.com


Pit Capitain

unread,
Oct 20, 2005, 10:13:14 AM10/20/05
to
Eric Mahurin schrieb:

> module Braces
> remove_method :foo
> end
>
> c.foo # => "[bar]"
>
> I really like this. I don't see anything you couldn't do with
> this that you can with the cut-based-AOP. And it seems so much
> simpler.

I like it too, but instead of having to remove methods from modules, it
would be better if we could "exclude" modules from the inheritance
chain. Will this be possible in Ruby 2?

Another question: how would I "preclude" a module to an instance?

Module: include <-> preclude
Instance: extend <-> ?? (pretend :-)

Regards,
Pit


Daniel Schierbeck

unread,
Oct 20, 2005, 10:26:13 AM10/20/05
to
+1

I only have one concern: I think the syntax is kinda weird. It resembles
the class definition syntax, but I can't see why it should. When you
write "class A < B" you're saying "class A inherits from class B" or
"class A is affected by class B". If we apply the same to "cut A < B",
it would be "cut A is affected by class B", which isn't the case. Why
not use "cut A > B", "cut A affects class C". The singleton syntax could
be like this "cut >> obj".


Just my .16 Yen
Daniel

Eric Mahurin

unread,
Oct 20, 2005, 10:31:52 AM10/20/05
to
--- Pit Capitain <p...@capitain.de> wrote:

> Eric Mahurin schrieb:
> > module Braces
> > remove_method :foo
> > end
> >
> > c.foo # => "[bar]"
> >
> > I really like this. I don't see anything you couldn't do
> with
> > this that you can with the cut-based-AOP. And it seems so
> much
> > simpler.
>
> I like it too, but instead of having to remove methods from
> modules, it
> would be better if we could "exclude" modules from the
> inheritance
> chain. Will this be possible in Ruby 2?

Yep, that might be useful too. So you'd do this instead:

class C
exclude Braces
end

Another end case you have to think about is if a class
precludes the same module twice. Does it wrap the method
twice? And if so, does "excluding" it remove both wraps.

> Another question: how would I "preclude" a module to an
> instance?
>
> Module: include <-> preclude
> Instance: extend <-> ?? (pretend :-)
>
> Regards,
> Pit

Yes, I was just thinking about that too. "pretend" was the
first that came to my mind too :) But, you could also do it
manually:

class <<obj;preclude XXX;end


Another possiblity for a name instead of "preclude" would be
"wrap":

class C
wrap Brackets
wrap Braces
end

c.foo # => "{[foo]}"

class C
unwrap Brackets
end

c.foo # => "{foo}"

Alexandru Popescu

unread,
Oct 20, 2005, 10:33:19 AM10/20/05
to
#: Christophe Grandsire changed the world a bit at a time by saying on 10/20/2005 2:20 PM :#

I would probably agree with you with some small exceptions:

1/ AspectJ was alien to java because it was meant to provide a full AOP implementation. Meanwhile,
considering AJ alien is like saying cut-s are alien to ruby, just because they are trying to
introduce a new idea.

2/ in a bottom-up approach as you are considering the cut-s approach, you can miss some of the top
views. And this will result in the impossibility to have this top scenarios implemented or working.

3/ if you consider cut-s just an implementation aspect of AOP support in Ruby, than I will agree
that it looks quite appealing. But I have read a full set of examples which are based directly on
them. I wasn't able to see pointcut definitions, and without them - as I already pointed - there is
no aop.

I am not trying to argue on the main idea or on the effort this RCR took. It is indeed a fantastic
effort and I appreciate it. I just feel that some aspects should be considered right from the
beginning instead of just ignoring them. We have the advantage that other solutions are pretty
advanced at this moment and learning from their past is a good thing to do.

respectfully,

Trans

unread,
Oct 20, 2005, 11:39:38 AM10/20/05
to
Hi Matz,

Yukihiro Matsumoto wrote:

> I understand the basic idea. How about introducing a new method
> e.g. "preclude" that works to intercept the methods in the target
> class/module, instead of cut. It would be a counterpart of "include"
> for mix-in.

Yes, this is in the RCR:

Additionally, Cuts exist in proxy form to allow modules to be
"premixed". This is analogous to proxy classes which allow modules to
mixin to the class hierarchy. So too does a proxy-cut include a module,
albeit preclusive rather the inclusive in its effect. We offer the
module command #preclude to serve as designator of this purpose.

module A
def m ; "<#{super}>" ; end
end
Class T
preclude A
def m ; "okay" ; end
end
T.new.m #=> "<okay>"


I am amazed how quickly you've latched onto the most probable usage. I
have known for sometime that "preclude" would be the most utilized part
of this. But I have avoided stressing it becuase it is important that
it too be supported by good foundation, which is the Cut. Just as there
is a *proxy-class* to *mixin* modules, there'd be a *proxy-cut* to
*premix* them. Although precluding modules will certainly be utilized
most, I do not see any benefit in hiding the underlying class which
facilitates them from the programmer.

OTOH, perhaps you have a different idea for the implementation of
precluded modules; one that avoids any sort of cut/proxy-cut class
altogether. If so, I must tell you, I am cautious of such an approach
because it implies "adding-on" rather than "integrating". IMHO,
integrating this "atomic-aspect" formally into the OO class heirarchy
would be of greater benefit to Ruby, and potentially influential on OOP
in general. From a comparitive perspective, it is the difference
between Ruby simply having an extra feature and Ruby having a new and
original object-oriented feature.

T.

Eric Mahurin

unread,
Oct 20, 2005, 12:05:58 PM10/20/05
to
--- Trans <tran...@gmail.com> wrote:

Trans/Peter,

What does a "cut" do that "preclude" doesn't? It seems like
you still can manage the AOP methods through modules instead of
cuts. And you can stack these. Can you give a scenario where
"preclude" doesn't "cut" it :)

I still think something like "wrap" would be a better word.
"preclude" may describe the inheritance hierarchy kind of, but
not the functionality from a user's perspective.


__________________________________
Yahoo! Music Unlimited
Access over 1 million songs. Try it free.
http://music.yahoo.com/unlimited/


Trans

unread,
Oct 20, 2005, 12:33:16 PM10/20/05
to
Hi--

Alexandru Popescu wrote:
> Hi!
>
> I would like to comment on this proposal. I can agree right from the beginning
> that the points here will be presented from a not-so-rubiesc perspective.
> the proposal looks like an method-interception framework, rather than a
> full blown aop solution.

Yes, in a way you are correct. Ruby provides enough reflective
functionality that it is not neccessary. In other words there is no
need for what you call "full-blown" aop b/c the system already supports
all that is neccessary to achieve full blown aop. This is not to say
there are no areas in which it can be improved, indeed there are. Cuts
is one of those. Peter and I already have developed much of the rest
too: ways to strengthen the hooks and callbacks as well as better EAOP
(event-based AOP) than provided by set_trace_func. But these are for
another day, and more importantly, they do not cover the the majority
of AOP usecase, which Cuts squarely target.

> The proposal is mixin together theoretical aspects of aop with Ruby specific
> implementation problems.

I would disagree completely. The proposal narrows down the core of AOP
(namely the 2nd form of AOP implemention) to a formal OOP construct.
The Cut can be implemented in any OOP system, from Simula 67 to
Smalltalk. In fact this has been all along and still is Very Important
to me. I did not want a construct suitable only to Ruby, but something
generally applicable.

> While this cannot be considered a real problem, what I have noticed is that one of > the main concepts of the AOP pointcuts are completely ignored.

Pointcuts are mentioned, and why there is no need to have a special
"pointcut thing". Pointcut is a concept of selecting joinpoints
--another abstract term, meaning the place in code to intercept. Well,
we have exactly that. You can specify on small scale of one class and
it's methods, or large scale using ObjectSpace. It is not neccessary to
make a pointcut thing when we already have those. But if you want you
could write your own extermely easily, probably in one line of code.

> The main idea behind AOP is to be able to define crosscutting concerns. This looks > pieces of functionality that can be used disregarding the OO nature of the > project.

Sorry, I do not full understanding. We do address crosscutting, and OO
nature.

> While at the first glance the method interception mechanism is one of most
> important aspects of AOP, there are a few distinction that must be considered:
> call vs execution, before, around, after pieces of advice.

before and after advice are subset of around advice. We decided it was
just easer to have the one than worry about three since before and
after are merely sugar of around. You are right about call vs.
execution though. In this case it a matter of the 80/20 rule. We make
80% of the need easy (though it's probably more like 99/1 in this
case). If you _must_ have call interception then there are more advance
techinuques to use, such as set_trace_func. We've also discussed
method_dispatching hook. But understand these have much greater impact
on performance than method interception. This is important reason call
interception is not specifically part of this RCR. (But who knows?
Maybe someone will come up with an easy idea for this too).

> While, maybe leaving alone all these aspects, may be a Ruby implementation
> constraint, they are valid AOP principles that will miss from the implementation.

There are some. Because Ruby is not 100% OOP, though it is very close,
you can not cut conditionals for example. You've pointed out call
interception already and there are other marginal areas. Ruby itself
has some limitations that effect this. Combined with Ruby's ability to
reflect on itself, Cut-based AOP covers the vast majoirty of AOP needs.
And as Ruby improves so does the reach of cuts.

T.

Trans

unread,
Oct 20, 2005, 12:42:13 PM10/20/05
to

Your .16 Yen is appreciated :) In fact we have discussed similar
notation:

class A > Ac
# advice
end

We decided against, mainly because it looks too much like normal
subclassing. though it is certaintly a possibility.

How I say 'cut Ac < A' is "cut Ac cuts A.", though I normally drop the
first 'cut', "Ac cuts A".

T.

Trans

unread,
Oct 20, 2005, 12:50:54 PM10/20/05
to

Eric Mahurin wrote:

> Another end case you have to think about is if a class
> precludes the same module twice. Does it wrap the method
> twice? And if so, does "excluding" it remove both wraps.

No. The idea is that it would use a proxy-cut, just as a module uses a
proxy-class. So like modules that are included, Once included they are
not included again. A limitation? Yes. But one we've come acustom to in
the way Ruby's inhertiance works.

Exluding aspect modules is potentially expensive operation, espeacilly
if you include and exclude a lot. But it could be interesting. I htink
it essentially amounts to selector namespaces.

T.

stevetuckner

unread,
Oct 20, 2005, 1:06:42 PM10/20/05
to
Trans wrote:

Please expand on that last sentence please. Could this cut feature be
used to implement selector namespaces?

Steve Tuckner

>T.
>
>
>
>
>

Trans

unread,
Oct 20, 2005, 3:01:51 PM10/20/05
to

Eric Mahurin wrote:

> What does a "cut" do that "preclude" doesn't? It seems like
> you still can manage the AOP methods through modules instead of
> cuts. And you can stack these. Can you give a scenario where
> "preclude" doesn't "cut" it :)

Given the implementation of proxy-cuts, it is basically the exact same
difference between class and module. If not familar with how a module
is inclued into the class hierarchy via a proxy-class, have a look in
Pickaxe. It explains it well. Also cuts aren't instatiable on their own
so they are even more like modules in that one respect. So the answer
is "very little".

There is one difference though that can in certain circumstance be
problematic if only a module solution were available: the Dynamic
Module Inclusion Problem. You can see this problem with normal modules.

module X
def x; 1; end
end

class C
include X
end

c = C.new

p c.x #=> 1

module Z
def z; "z"; end
end

module X ; include Z ; end

p c.z #=> NoMethodError

We've include X into class C, then instatiated an instance of it. If
later we include another module Z into module X, it will not show up in
C. If we had included Z directly into class C instead we would not have
this problem. In the same manner this would effect precluded modules,
and while not an utter show stopper, it is more likely to occur for
cuts b/c of the nature of AOP, esspecially if were talking about making
them even more dynamic, including and extracting them on the fly.

Note, the Dynamic Module Problem is an ackowledged issue with Ruby and
has nothing to do with cuts themselves. From what I understand, it is
not a simple problem to solve and would take a great deal of effort and
a good bit of alteration to Ruby --if it is even efficenty possible.

Other then that I'm not sure if there is anything *undoable*. You can
program Ruby without every subclassing too; modules do everyhting you
need. But even so underthehood the subclass is still there in proxy
form. So I'm not sure if there is really anything to gain from not
providing the Cut to the end user given that it's already underneath
anway.

And actually it is nicer to use when your just need is to cut a
specific class:

class C
def x ; '1' ; end
end

cut A < C
def s ; '{' + super + '}' ; end
end

vs.

class C
def x ; '1' ; end
end

module A
def s ; '{' + super + '}' ; end
end

class C
preclude A
end

There is no need to reopeon the class.

Ah, there is one more thing. Using Cuts could allow for cutting cuts, a
way to insert advice prior to other prexisting advice.

class C
def x ; '1' ; end
end

cut A < C
def s ; '{' + super + '}' ; end
end

C.new.x #=> {1}

cut B < A
def s ; '[' + super + ']' ; end
end

C.new.x #=> {[1]}

Notice cuts stack inversely when cutting each other. We never decided
if this would be allowed or not, but it is a possibility. It would not
be as tidy if only modules were availble, moreovor it would definitely
come-up against the Dynamic Module Inclusion Problem.

> I still think something like "wrap" would be a better word.
> "preclude" may describe the inheritance hierarchy kind of, but
> not the functionality from a user's perspective.

I didn't like #preclude at first, but nothing ever felt as right
considering its parallel to #include. There is #prepend, but I'm sure
that will be matched against #append_features which #include uses. But
if you think about it preclude means essentially "forgone conclusion".
That's pretty close.

T.

Alexandru Popescu

unread,
Oct 20, 2005, 3:25:31 PM10/20/05
to
#: Trans changed the world a bit at a time by saying on 10/20/2005 6:36 PM :#

> Hi--
>
> Alexandru Popescu wrote:
>> Hi!
>>
>> I would like to comment on this proposal. I can agree right from the beginning
>> that the points here will be presented from a not-so-rubiesc perspective.
>> the proposal looks like an method-interception framework, rather than a
>> full blown aop solution.
>
> Yes, in a way you are correct. Ruby provides enough reflective
> functionality that it is not neccessary. In other words there is no
> need for what you call "full-blown" aop b/c the system already supports
> all that is neccessary to achieve full blown aop. This is not to say
> there are no areas in which it can be improved, indeed there are. Cuts
> is one of those. Peter and I already have developed much of the rest
> too: ways to strengthen the hooks and callbacks as well as better EAOP
> (event-based AOP) than provided by set_trace_func. But these are for
> another day, and more importantly, they do not cover the the majority
> of AOP usecase, which Cuts squarely target.
>

Sorry that I have to say it: no it doesn't support. Should we talk about aspect instantion
strategies? Should we talk about field read/write access? Should we talk about flow based pointcuts?
Probably this will give raise of an answer that these can be achieved doing X or Y trick. I agree.
But the principle behind a framework should be not to require another tricks for making it work.

>> The proposal is mixin together theoretical aspects of aop with Ruby specific
>> implementation problems.
>
> I would disagree completely. The proposal narrows down the core of AOP
> (namely the 2nd form of AOP implemention) to a formal OOP construct.
> The Cut can be implemented in any OOP system, from Simula 67 to
> Smalltalk. In fact this has been all along and still is Very Important
> to me. I did not want a construct suitable only to Ruby, but something
> generally applicable.
>
>> While this cannot be considered a real problem, what I have noticed is that one of > the main concepts of the AOP pointcuts are completely ignored.
>
> Pointcuts are mentioned, and why there is no need to have a special
> "pointcut thing". Pointcut is a concept of selecting joinpoints
> --another abstract term, meaning the place in code to intercept. Well,
> we have exactly that. You can specify on small scale of one class and
> it's methods, or large scale using ObjectSpace. It is not neccessary to
> make a pointcut thing when we already have those. But if you want you
> could write your own extermely easily, probably in one line of code.
>

I have said it too many times: I am not a Ruby dev, so this one line of code pointcut support is not
clear to me. Can you help me out? I want a pointcut that will match all calls to a db operation
method so that I can crosscut the transaction concerns.

>> The main idea behind AOP is to be able to define crosscutting concerns. This looks > pieces of functionality that can be used disregarding the OO nature of the > project.
>
> Sorry, I do not full understanding. We do address crosscutting, and OO
> nature.
>
>> While at the first glance the method interception mechanism is one of most
>> important aspects of AOP, there are a few distinction that must be considered:
>> call vs execution, before, around, after pieces of advice.
>
> before and after advice are subset of around advice. We decided it was
> just easer to have the one than worry about three since before and
> after are merely sugar of around. You are right about call vs.
> execution though. In this case it a matter of the 80/20 rule. We make
> 80% of the need easy (though it's probably more like 99/1 in this
> case). If you _must_ have call interception then there are more advance
> techinuques to use, such as set_trace_func. We've also discussed
> method_dispatching hook. But understand these have much greater impact
> on performance than method interception. This is important reason call
> interception is not specifically part of this RCR. (But who knows?
> Maybe someone will come up with an easy idea for this too).
>

Before and after advices can be seen as subset of around, but (at least) theoretically speaking they
are not. The around advice is the only one that can control the program flow; the others are not.

I am not aware of what are those percentages: 99/1 means that out of 100 pointcuts 99 are execution
pointcuts?


>> While, maybe leaving alone all these aspects, may be a Ruby implementation
>> constraint, they are valid AOP principles that will miss from the implementation.
>
> There are some. Because Ruby is not 100% OOP, though it is very close,
> you can not cut conditionals for example. You've pointed out call
> interception already and there are other marginal areas. Ruby itself
> has some limitations that effect this. Combined with Ruby's ability to
> reflect on itself, Cut-based AOP covers the vast majoirty of AOP needs.
> And as Ruby improves so does the reach of cuts.
>
> T.
>
>
>

You don't even want to expose conditionals, or some weird (and unstable) points in program execution.

Eric Mahurin

unread,
Oct 20, 2005, 3:40:31 PM10/20/05
to
--- Trans <tran...@gmail.com> wrote:
> Eric Mahurin wrote:
>
> > What does a "cut" do that "preclude" doesn't? It seems
> like
> > you still can manage the AOP methods through modules
> instead of
> > cuts. And you can stack these. Can you give a scenario
> where
> > "preclude" doesn't "cut" it :)

[...]

> Note, the Dynamic Module Problem is an ackowledged issue with
> Ruby and
> has nothing to do with cuts themselves. From what I
> understand, it is
> not a simple problem to solve and would take a great deal of
> effort and
> a good bit of alteration to Ruby --if it is even efficenty
> possible.
>
> Other then that I'm not sure if there is anything *undoable*.

So, let's start with the simple preclude/wrap module concept.
Make that the basis instead of "cut". Implementation-wise it
may be very similar to what's needed for "cut". If possible,
management of these precluded/wrapped modules could be
provided.


__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com


Peter Vanbroekhoven

unread,
Oct 20, 2005, 5:12:08 PM10/20/05
to
On Fri, 21 Oct 2005, Eric Mahurin wrote:

> So, let's start with the simple preclude/wrap module concept.
> Make that the basis instead of "cut". Implementation-wise it
> may be very similar to what's needed for "cut". If possible,
> management of these precluded/wrapped modules could be
> provided.

It's obvious that you don't like cuts (you've stated such before). That's
fine. But we do like cuts. But I don't quite understand what you find so
complex about cuts and so simple about preclude modules.

One of the reasons I like cuts is maybe best explained with a comparison.
Say I want to wrap some goods using a plastic wrapping. Given that all
these goods are about the same size, I can use the same kind of wrapping.
But given that these goods have different shapes, the wrapping will have
to folded differently each time. So now make these goods different
classes, the wrapping a module and the wrapping in different shapes cuts.
So even if the module is reusable, you often want it to adapt to the class
it cuts (or precludes). A single module cannot adapt to multiple classes
just like that, it can have only a single set of methods. A cut is
essentially an instance of a preclusion if you will, which can adapt to
the class it cuts, but it can still reuse the module by including it. And
I'm sure this can be accomplished with just preclusion alone --after all,
Ruby is a powerful language-- but in our opinion the use of a cut is
cleaner. And note that this adaptation is important, as this is what is
needed to handle things like pointcuts specified through wildcards.

Now if you don't want to go through cuts, we can provide a method that
simply precludes a module, sure. But I want to keep cuts in there because
they provide us with a clean, simple way to differentiate advice for
different class even if it is reusing functionality from a module. We
found it so important that it deserves to be a separate concept. A cut
potentially gives you a handle on a preclusion itself, specific for the
class it is precluded in, and it could serve as an entry point for
call-backs that are needed to have advice react to each class it is
advicing. Basically, a module can be used for functionality that is shared
(which is what mix-ins are for), a cut can be used for functionality that
is specific to each class the advice is applied to, and mix-ins can again
be used to build that class-specific functionality.

If Matz rules that cuts are not acceptable and precluded modules are, then
so be it. But as I see it, it will make a common AOP practice more
involved and less clean. Opinions may vary though.

Peter


Trans

unread,
Oct 20, 2005, 5:47:24 PM10/20/05
to

Alexandru Popescu wrote:
> Sorry that I have to say it: no it doesn't support. Should we talk about aspect instantion
> strategies? Should we talk about field read/write access? Should we talk about flow based pointcuts?
> Probably this will give raise of an answer that these can be achieved doing X or Y trick. I agree.
> But the principle behind a framework should be not to require another tricks for making it work.

What do you want to say? There are a number of Dependency Injection
frameworks being worked on for Ruby, intercepting instance variable
access would be a fine feature, maybe we'll get that one day, but
should we wait for that before moving foward? Likewise for control
flow. Talk about being tricky. Do you consider Ruby's hooks and
callbacks tricks? I do not. They are powerful and efficient predefined
"joinpoints" that go a long way toward filling-out AOP for Ruby.

Please understand, I am not trying to build a framework. I am trying to
lay a simple foundation. One that we all understand and thus can share.
Try to propose an RCR for what you say and we will never stop
scwabbling over details. Build such a framework and maybe (a big
maybe), it will make the standard library, but it will not make core
Ruby. And when and if you go to do so, don't be suprised when you
think, "hmmm those cuts sure could make some of this easier".

Our proposal states clearly "Make the Common Easy, and the Uncommon
Possible" --it's the 80/20 rule. That's what were after here. We can
improve support for that last 20 down the road. But lets get a nice
solid basis we can all use now.

> > Pointcuts are mentioned, and why there is no need to have a special
> > "pointcut thing". Pointcut is a concept of selecting joinpoints
> > --another abstract term, meaning the place in code to intercept. Well,
> > we have exactly that. You can specify on small scale of one class and
> > it's methods, or large scale using ObjectSpace. It is not neccessary to
> > make a pointcut thing when we already have those. But if you want you
> > could write your own extermely easily, probably in one line of code.
> >
>
> I have said it too many times: I am not a Ruby dev, so this one line of code pointcut support is not
> clear to me. Can you help me out? I want a pointcut that will match all calls to a db operation
> method so that I can crosscut the transaction concerns.

Sincere? Just this "wee" problem? A little scarse on detail? Let's not
make it too easy on me now! But hey, no problem! ;)

class JoinPoint
attr_reader :klass, method
def initialize( klass, meth )
@klass = klass
@method = method.to_s
end
end

def pointcut(&pcut)
ObjectSpace.each_object(Module).each { |base|
adv = {}
base.instance_methods(false).each{ |m|
adv[m] = pcut.call( JoinPoint.new( base,m ) )
}
if base.is_a?(Class)
cut.new(base) do
adv.each { |a,p| define_method(a,&p) }
end
else
aspect = mod.new do
adv.each { |a,p| define_method(a,&p) }
end
base.module_eval { preclude aspect }
end
}
end

pointcut do |jp|
if jp.method =~ /^database/
lambda{ |*args| DB.transaction{ super } }
end
end

Okay took about ten minutes....okay, fifteen. Please excuse any
simpleton bugs, I really don't feel like testing it. You get the
piture.

> Before and after advices can be seen as subset of around, but (at least) theoretically speaking they
> are not. The around advice is the only one that can control the program flow; the others are not.

You can use around and not control the progam flow. Just don't do it.
We don't need safegaurads for this, we use testsuites.

> I am not aware of what are those percentages: 99/1 means that out of 100 pointcuts 99 are execution
> pointcuts?

I'm just generalizing about usecase scenarios. Like 80 out 100 cases,
or 99 out of a 100 cases. Not exact. Just a general sense of things.

> > There are some. Because Ruby is not 100% OOP, though it is very close,
> > you can not cut conditionals for example. You've pointed out call
> > interception already and there are other marginal areas. Ruby itself
> > has some limitations that effect this. Combined with Ruby's ability to
> > reflect on itself, Cut-based AOP covers the vast majoirty of AOP needs.
> > And as Ruby improves so does the reach of cuts.
> >

> You don't even want to expose conditionals, or some weird (and unstable) points in program execution.

Oh sure you do! My MethodProbe would eat it up :)

T.

Alexandru Popescu

unread,
Oct 20, 2005, 6:31:56 PM10/20/05
to
Most probably my comments are missinterpretted. I am not trying to argue the value behind the RCR.
Neither I contradict it's power. I am just trying to point that it is missing important features.
Once we agree on this, the discussion may proove fruitful. Otherwise, there is no reason to continue it.

I surely would like to write my own one. As said I am not ruby expert, and when time back I was
asking for the community help (and should I mention that I asked your personal help?) on this matter
I got some form of refusal in the form: you can do this trick and that trick and you will have
something that is AOP. No, it is not; but I can go on with my life :-).

Now, comments inlined:

#: Trans changed the world a bit at a time by saying on 10/20/2005 11:52 PM :#


> Alexandru Popescu wrote:
>> Sorry that I have to say it: no it doesn't support. Should we talk about aspect instantion
>> strategies? Should we talk about field read/write access? Should we talk about flow based pointcuts?
>> Probably this will give raise of an answer that these can be achieved doing X or Y trick. I agree.
>> But the principle behind a framework should be not to require another tricks for making it work.
>
> What do you want to say? There are a number of Dependency Injection
> frameworks being worked on for Ruby,

I was not talking about innexistent good frameworks in Ruby. I was talking about the principles of a
new framework.

> intercepting instance variable
> access would be a fine feature, maybe we'll get that one day, but
> should we wait for that before moving foward? Likewise for control
> flow. Talk about being tricky. Do you consider Ruby's hooks and
> callbacks tricks? I do not. They are powerful and efficient predefined
> "joinpoints" that go a long way toward filling-out AOP for Ruby.
>
> Please understand, I am not trying to build a framework. I am trying to
> lay a simple foundation. One that we all understand and thus can share.
> Try to propose an RCR for what you say and we will never stop
> scwabbling over details. Build such a framework and maybe (a big
> maybe), it will make the standard library, but it will not make core
> Ruby. And when and if you go to do so, don't be suprised when you
> think, "hmmm those cuts sure could make some of this easier".
>
> Our proposal states clearly "Make the Common Easy, and the Uncommon
> Possible" --it's the 80/20 rule. That's what were after here. We can
> improve support for that last 20 down the road. But lets get a nice
> solid basis we can all use now.
>

I have still to disagree with this percentages. But for the moment, it is not so important.


Ohhh... I got the idea... but I am wondering where is that "simple 1 line of code" :-).

Moreover: a pointcut is not expressed only in terms of class and methods. I don't call my methods
'database'. And I am wondering where is the modularity of this piece of code. How can I reuse it?
(copy and paste?)

I am stopping now, as I may already sound harsh and this is not my intention.

I surely would prefere to write instead of the above script:

class TransactionAspect < AOP::Aspect
pointcut: transactionalMethod => "*#save*(..) || *#delete*(..)"

before: transactionalMethod
def assureTransaction
[...]
end
end


>> Before and after advices can be seen as subset of around, but (at least) theoretically speaking they
>> are not. The around advice is the only one that can control the program flow; the others are not.
>
> You can use around and not control the progam flow. Just don't do it.
> We don't need safegaurads for this, we use testsuites.
>
>> I am not aware of what are those percentages: 99/1 means that out of 100 pointcuts 99 are execution
>> pointcuts?
>
> I'm just generalizing about usecase scenarios. Like 80 out 100 cases,
> or 99 out of a 100 cases. Not exact. Just a general sense of things.
>
>> > There are some. Because Ruby is not 100% OOP, though it is very close,
>> > you can not cut conditionals for example. You've pointed out call
>> > interception already and there are other marginal areas. Ruby itself
>> > has some limitations that effect this. Combined with Ruby's ability to
>> > reflect on itself, Cut-based AOP covers the vast majoirty of AOP needs.
>> > And as Ruby improves so does the reach of cuts.
>> >
>> You don't even want to expose conditionals, or some weird (and unstable) points in program execution.
>
> Oh sure you do! My MethodProbe would eat it up :)
>
> T.
>
>
>

Not sure what is MethodProbe. What I am sure is that in the long run an instabel pointcut system
that exposes such `volatile´ infos will not pay back the effort.

cheers,

./alex
--
.w( the_mindstorm )p.

Trans

unread,
Oct 20, 2005, 6:33:15 PM10/20/05
to
> I am not trying to build a framework. I am trying to lay a simple foundation.

I should probably be saying "We" here, rather than "I", though I do not
presume to neccessarily speak for Peter.

T.

Trans

unread,
Oct 20, 2005, 7:12:21 PM10/20/05
to

Alexandru Popescu wrote:
> Most probably my comments are missinterpretted. I am not trying to argue the value behind the RCR.
> Neither I contradict it's power. I am just trying to point that it is missing important features.
> Once we agree on this, the discussion may proove fruitful. Otherwise, there is no reason to continue it.

I have already agreed. We are not promising the world. Like I said we
focused on most common potential uses.

> I surely would like to write my own one. As said I am not ruby expert, and when time back I was
> asking for the community help (and should I mention that I asked your personal help?) on this matter
> I got some form of refusal in the form: you can do this trick and that trick and you will have
> something that is AOP. No, it is not; but I can go on with my life :-).

Alexandru, we are busy too. And we have our own ideas too. If you
really want to do this, then okay. I am not against helping. But I have
a lot on my plate and must squeeze in. Also if you want to manipulate
core, I'm not really the goto man, I code Ruby. Peter's the C expert. I
understand what you are saying, I'm not trying discourage you, but I'm
not a big believer in the Aspect/J-kind of design. It's heavy
"top-down". An that's what I was trying to say before. I think there's
more fluidity in "build-up". You might look at that as tricks, but
those tricks are they very thing you will use to build a
full-framework. How do I know? Because I've basically done it.

> Now, comments inlined:


>
> I was not talking about innexistent good frameworks in Ruby. I was talking about the principles of a
> new framework.

Okay.

> I have still to disagree with this percentages. But for the moment, it is not
> so important.

Sure. That's fine.

> Ohhh... I got the idea... but I am wondering where is that "simple 1 line of code" :-).

Hey, I said I could write *a* pointcut not *any* pointcut. Besides I
wanted to give you a show! :)

> Moreover: a pointcut is not expressed only in terms of class and methods. I don't call my methods
> 'database'. And I am wondering where is the modularity of this piece of code. How can I reuse it?
> (copy and paste?)

You expected all that in one line of code? :) Beside you did not
specify those things.

> I am stopping now, as I may already sound harsh and this is not my intention.

Well, I hope you are not put off. It is a good discussion.

> I surely would prefere to write instead of the above script:
>
> class TransactionAspect < AOP::Aspect
> pointcut: transactionalMethod => "*#save*(..) || *#delete*(..)"
>
> before: transactionalMethod
> def assureTransaction
> [...]
> end
> end

I have written parts of very similar framework. Others have too. What
is "new" about your framework? I would be interested to hear. Why don't
you contact me private email. We can discuss and I can see how much I
can help if you really want. I am certainly not against an interesting
full framework, but such just doesn't deter from Cuts.

Thanks,
T.

Alexandru Popescu

unread,
Oct 20, 2005, 7:32:36 PM10/20/05
to
#: Trans changed the world a bit at a time by saying on 10/21/2005 1:16 AM :#

> Alexandru Popescu wrote:
>> Most probably my comments are missinterpretted. I am not trying to argue the value behind the RCR.
>> Neither I contradict it's power. I am just trying to point that it is missing important features.
>> Once we agree on this, the discussion may proove fruitful. Otherwise, there is no reason to continue it.
>
> I have already agreed. We are not promising the world. Like I said we
> focused on most common potential uses.
>
>> I surely would like to write my own one. As said I am not ruby expert, and when time back I was
>> asking for the community help (and should I mention that I asked your personal help?) on this matter
>> I got some form of refusal in the form: you can do this trick and that trick and you will have
>> something that is AOP. No, it is not; but I can go on with my life :-).
>
> Alexandru, we are busy too. And we have our own ideas too. If you
> really want to do this, then okay. I am not against helping. But I have
> a lot on my plate and must squeeze in. Also if you want to manipulate
> core, I'm not really the goto man, I code Ruby. Peter's the C expert. I
> understand what you are saying, I'm not trying discourage you, but I'm
> not a big believer in the Aspect/J-kind of design. It's heavy
> "top-down". An that's what I was trying to say before. I think there's
> more fluidity in "build-up". You might look at that as tricks, but
> those tricks are they very thing you will use to build a
> full-framework. How do I know? Because I've basically done it.
>

Good to hear that both of us have done it. I have to agree that till now everything I've done in
this direction is theory and Java only.

There is not such thing existing. That time back when I opened the discussion I had the time to find
out what you ruby-guys think about it. Unfortunately, the feedback wasn't sufficient for me to get
me started, so I backed to my Java AOP things.

Nobody (in fact I am speaking just for myself) is trying to take you away from Cuts. My experience,
just made me point you out the missing points. Probably, oposed to the majority here, I am very
happy to still be doing Java, so there is no rush for me ;-). Ruby seemed to me young in this field,
and just wanted to hint that some wheels are not so circle as I assumed.

Probably it would be interesting to start doing the cuts and see how we can build over it.
Unfortunately, I still cannot see solutions for some of the points I have mentioned previously.

regards,

Ryan Leavengood

unread,
Oct 21, 2005, 12:35:56 AM10/21/05
to
On 10/20/05, Alexandru Popescu <the.mindstor...@gmail.com> wrote:
>
> Probably it would be interesting to start doing the cuts and see how we can build over it.
> Unfortunately, I still cannot see solutions for some of the points I have mentioned
> previously.

I have tried to follow along on this *very long* and verbose thread,
but one thing I wanted to comment on here was that you must be careful
in not trying to "change the world" so to speak in one small RCR. That
almost guarantees that Matz won't accept it (I wouldn't either.)

I think the approach that Peter and Trans are following is the best.
Have a well thought out and relatively small RCR that will have a
better chance of being accepted. When and if that happens, it can then
be determined if something is lacking and then further RCRs can be
proposed to continue the gradual evolution of the Ruby AOP system.

Something I have learned all too well in my life is that trying to
achieve perfection and completion on the first try in any project is a
recipe for failure and disappointment. I don't think there is anything
in the nature of the cut's RCR that would preclude adding the things
you want Alex (though I certainly could be wrong, since I'm not AOP
expert), so I fail to see your concern.

Try to think evolution, no revolution.

Regards,
Ryan


Alexandru Popescu

unread,
Oct 21, 2005, 3:50:09 AM10/21/05
to
#: Ryan Leavengood changed the world a bit at a time by saying on 10/21/2005 6:35 AM :#

Thanks Ryan. I agree with you on most of the above things. Indeed my mails can look like revolution
instead of evolution, as you are saying. I was afraid that this will be the immediate feeling about
them. In fact, their real intentions is to show the steps of evolution an aop may pass in a short
and long run.
Comming from a few years of study and work in the aop field, made me ask if the current RCR is/will
be able to cope with some of the things defined by aop theory (and supproted in some other solutions).
In Java this is happening for a couple of years. The most important aop frameworks (or solutions or
implementations, doesn't really matter the name) have passed through all these small steps:
- AspectWerkz have been redesigned 3 times
- AspectJ has changed it's internals for a couple of times too
- we are seeing movements of adding support for AOP at the virtual machine level (BEA already did
it, Sun has started providing something in this direction too).

I really hope that my messages will be interpretted the way they were intended and not as a
counter-argue against the RCR.

thanks for your time,

Daniel Schierbeck

unread,
Oct 21, 2005, 5:26:21 AM10/21/05
to

I just don't think the lesser than character should be used when it
already has a certain meaning. I think the cut keyword is a good idea,
but the < should be a >. Again, that's just my opinion ;)

cut A > B; end
cut >> obj; end


Cheers,
Daniel

Christophe Grandsire

unread,
Oct 21, 2005, 5:45:05 AM10/21/05
to
Selon Daniel Schierbeck <daniel.s...@gmail.com>:

>
> I just don't think the lesser than character should be used when it
> already has a certain meaning. I think the cut keyword is a good idea,
> but the < should be a >. Again, that's just my opinion ;)
>
> cut A > B; end
> cut >> obj; end
>

I disagree. Cuts are, for all purposes, transparent subclasses. They are
implemented in such a way, and describing them like that just *makes sense*. So
it makes also sense to use < instead of >. > looks to me like Sather's
superclassing ability (and even if you don't know Sather, it's just natural if
one knows that < means subclassing to take > to mean superclassing), and cuts
aren't superclasses, especially since you can have more than one cut per class,
and Ruby is supposed to be single-inherited. Calling cuts transparent subclasses
really was the thing that made me understand their functionality, and I feel >
goes against that definition.

I understand why you are proposing such a syntax. I just feel people would get
the wrong impression from it.

Eric Mahurin

unread,
Oct 21, 2005, 8:31:27 AM10/21/05
to

I don't like the cut syntax either. It doesn't seem to
describe what it is doing very well. But, I don't think the
above is a good solution either.

To me, making a cut into a class is analogous to reopening a
class. The difference is that super and superclass refer to
the original class (or another cut in between) for cut and the
parent class when simply reopening a class. Here is what I
mean:

class A
def foo;"A";end
end

class B1 < A
def foo;"B";end
end

class B2 < A
def foo;"B";end
end

b1 = B1.new
b1.foo # => "B"

b2 = B2.new
b2.foo # => "B"

# super : A.instance_method(:foo).bind(self).call
class B1
def foo
"[" + super + "]"
end
end
b1.foo # => "[A]"

# modifies B2, inserting a cut in the inheritance chain
# super : B2.instance_method(:foo).bind(self).call
cut B2cut < B2
def foo
"[" + super + "]"
end
end
b2.foo # => "[B]"

# super : B1.instance_method(:foo).bind(self).call
class <<b1
def foo
"{" + super + "}"
end
end
b1.foo # => "{[A]}"

# super : B2.instance_method(:foo).bind(self).call
b2_meta_class = class <<b2
def foo
"<" + super + ">"
end
self
end
b2.foo # => "<[B]>"

# super : b2_meta_class.instance_method(:foo).bind(self).call
cut <<b2
def foo
"{" + super + "}"
end
end
b2.foo # => "{<[B]>}"


The syntax is not consistent:

class B meta-class of b
------- ---------------
reopen class B ... end class <<b ... end
cut cut Bcut < B ... end cut <<b ... end


Has the "cut <<" syntax been implemented in the patch?


__________________________________
Yahoo! FareChase: Search multiple travel sites in one click.
http://farechase.yahoo.com


Eric Mahurin

unread,
Oct 21, 2005, 8:43:15 AM10/21/05
to
One more thing. This RCR introduces a new reserved word to the
language: "cut". This will break any code already using "cut"
as a variable or method name (and calling it with no receiver).
An additional reserved word should not be introduced to the
language unless you really need it. So far, you haven't
demonstrated that a "cut" really provides anything else useful
over what you could do with the #preclude part of your RCR.
#preclude would just be another method so it shouldn't cause
compatibility issues like "cut".

Trans

unread,
Oct 21, 2005, 9:34:29 AM10/21/05
to

Eric Mahurin wrote:
> One more thing. This RCR introduces a new reserved word to the
> language: "cut". This will break any code already using "cut"
> as a variable or method name (and calling it with no receiver).
> An additional reserved word should not be introduced to the
> language unless you really need it.

Yes it does introduce the keyword cut. We have examined source and
detmined 'cut' is not used except in one place, a method in Tk. We gave
this careful consideration, weighed our opitons, consider alternate
names, and so. In the end we felt the succinctness of the word, its
relation to term cross-cutting and of course what it provides,
outweighed the sacrifice of this one use.

> So far, you haven't
> demonstrated that a "cut" really provides anything else useful
> over what you could do with the #preclude part of your RCR.
> #preclude would just be another method so it shouldn't cause
> compatibility issues like "cut".

That is a very blanket statement. And not correct. Both Peter and I
have given very good reasons to this effect (and we have resson to
suspect there are more). You may not agree with our reasons, but it
would be preferable if you addressed our points directly rather then
make such a broad claim. The problem I have with your take is that is
based essentially on the "look" of defining a cut. Peter and I are
considering it from a deeper perspective of funtionality, much of which
can be quite subtle.

T.

Trans

unread,
Oct 21, 2005, 10:03:00 AM10/21/05
to
Sorry for the delay steve. Mnay questions...

stevetuckner wrote:

> Please expand on that last sentence please. Could this cut feature be
> used to implement selector namespaces?

I cannot say for certain if it would be complete solution, but if cuts
could be "activated" and "deactived" on the fly it would be essentially
namespace selectors.

Simple Examples:

class A


def x; 1 ; end
end

cut Ac < A
def x ; 2 ; end
end

a = A.new

a.x #=> 2

Ac.mute # good interface for this?

a.x #=> 1

Ac.unmute

a.x #=> 2

That's the basic functionality of a namespace selector. So we should be
able to build on this to create namespace interface.

T.

Peter Vanbroekhoven

unread,
Oct 21, 2005, 11:12:20 AM10/21/05
to
On Fri, 21 Oct 2005, Eric Mahurin wrote:

> I don't like the cut syntax either. It doesn't seem to
> describe what it is doing very well. But, I don't think the
> above is a good solution either.
>
> To me, making a cut into a class is analogous to reopening a
> class. The difference is that super and superclass refer to
> the original class (or another cut in between) for cut and the
> parent class when simply reopening a class. Here is what I
> mean:

I see. So is that the problem? You have a different concept in your head,
cuts don't mesh with that concept, so cuts should go. The concept you just
mentioned, and which is what we started from two years ago, is one we
found flawed. What we want to advocate with cuts is to do AOP by adding a
layer to a class. That layer is essential to our proposal. So it is
certainly not reopening a class, it is like adding a layer on top. And
that is what subclassing does too, it adds a layer on top of the subclass,
hence a syntax like that of subclassing. The difference is in how that
layer is used, not in how it is defined. This layering approach makes
managing these wrapper methods rubyesc. And managing them is of the
essence. To us that was what was missing from Matz' approach at method
combination. So I want to stress, it is not like reopening a class. Our
point is exactly that the methods of the class and those of the layers on
top are separate. This means they can be redefined independently in a
simple and Rubyesc way. Of course if you just want to add a little wrapper
method to a method and never look back to it again --you're giving the
impression that you see this as the value of all this-- then I'm sure that
our approach does not make sense.

<snipped the code>

>
>
> The syntax is not consistent:
>
> class B meta-class of b
> ------- ---------------
> reopen class B ... end class <<b ... end
> cut cut Bcut < B ... end cut <<b ... end

Well, for the moment the patch does not allow this (I'm not claiming the
patch is perfect, or even does all that we want it to do), but the full
comparison would be this:

open class B < A ... end class <<b ... end
cut cut B < A ... end cut <<b ... end

reopen class B ... end class <<b ... end

'recut' cut B ... end cut <<b ... end

open' class B ... end
cut' cut B ... end

This seems consistent enough to me.

What I've always found a pity though, is that the meta-class declaratiopn
does not allow naming the meta-class, maybe like this:

class Meta_b << b ; end

And somethimes it's a pity that the usual class syntax cannot be used to
reopen a class that's not assigned to a constant. That's slightly annoying
when working with anonymous classes. It would be nice if instead of only a
constant, any variable culd be allowed, like this:

c = Class.new(A)
class c
end

Or:

class c < A
end

> Has the "cut <<" syntax been implemented in the patch?

Yes.

Peter


Jacob Fugal

unread,
Oct 21, 2005, 12:30:41 PM10/21/05
to
On 10/20/05, Alexandru Popescu <the.mindstor...@gmail.com> wrote:
> class TransactionAspect < AOP::Aspect
> pointcut: transactionalMethod => "*#save*(..) || *#delete*(..)"
>
> before: transactionalMethod
> def assureTransaction
> [...]
> end
> end

How about this?

Aspect.before( '*#save*', '*#delete*' ) do
# advice
end

Implementation[1]:

module Aspect
def before( *cut_specifications, &advice )
cut_specifications.each do |spec|
unless PointCut === spec
spec = PointCut.new( spec )
end
spec.joinpoints.each do |joinpoint|
joinpoint.before &advice
end
end
end
end

class PointCut
attr_reader :joinpoints
def initialize( *cuts )
@joinpoints = []
cuts.each do |cut|
module_pattern, method_pattern = cut.split /#/
module_pattern = Regexp.new /^#{module_pattern}$/
method_pattern = Regexp.new /^#{method_pattern}$/
ObjectSpace.each_object(Module).each do |base|
if module_pattern.match( base.to_s )
adv = {}
base.instance_methods(false).each do |meth|
if method_pattern.match( meth.to_s )
@joinpoints << JoinPoint.new( base, meth )
end
end
end
end
end
end

class JoinPoint


def initialize( klass, meth )
@klass = klass
@method = meth

end

def before( &advice )
if Class === @klass
Cut.new( @klass ) do
define_method @method.to_s &advice


end
else
aspect = mod.new do

define_method(a,&p)
end
@klass.module_eval do
preclude aspect
end
end
end
end

Jacob Fugal

[1] COMPLETELY UNTESTED. Most likely buggy, ineffecient and/or
incomplete. But should give an idea of how to do a cross cut like
Alexandru wanted using Cuts as a basis.


Peter Vanbroekhoven

unread,
Oct 21, 2005, 2:07:08 PM10/21/05
to
On Fri, 21 Oct 2005, Eric Mahurin wrote:

> One more thing. This RCR introduces a new reserved word to the
> language: "cut". This will break any code already using "cut"
> as a variable or method name (and calling it with no receiver).
> An additional reserved word should not be introduced to the
> language unless you really need it. So far, you haven't
> demonstrated that a "cut" really provides anything else useful
> over what you could do with the #preclude part of your RCR.
> #preclude would just be another method so it shouldn't cause
> compatibility issues like "cut".

The syntax of cuts parallels that of subclassing, preclude parallels
module inclusion. I think these are two valid views, and none is less
intuitive than the other because it borrows its syntax from another
concept in the language. So I think the discussion comes down to this: is
it more class-like, or more module-like?

In our opinion (I speak only for myself, but I'll say our nonetheless) it
is more class-like. The reason is that this object with the wrapper
methods extends a given class. It does so like a subclass extends a class.
And just like a subclass, that wrapper thing inherits the interface of the
class it wraps. It's that interface that it needs to work with. In many
cases it will have to be taylored to that interface. Especially within
AOP. Say I want to build an aspect that notifies me if a bang method is
called on a given class. When I apply that aspect to say String, the set
of wrapper methods will be different than for say Fixnum. Hence each
instantiation of an aspect will often differ in the methods it provides,
and maybe even in their definitions. The cut is in a way an instantiation
of an aspect. Which does not mean that these cuts can't have common
behavior. But that's what modules are for. The behavior that is not reused
belongs in a cut, just like with classes. Having these cuts makes some
things surprisingly simple (note: this only works with a new version of
the patch, which is not yet available because I'm still working on it):

class BangCut < Cut
def initialize(sup)
super
sup.instance_methods(true).grep(/!$/) do |sym|
add_notifier(sym)
end
end
def cut_method_added(sym)
add_notifier(sym) if /!$/ =~ sym.to_s
end
def add_notifier(sym)
module_eval %{
def #{sym}(*args)
puts "calling #{sym}"
super
end
}
end
end

cut = BangCut.new(String)

class String
def scramble!
length.times do
r1 = rand(length)
r2 = rand(length)
self[r1], self[r2] = self[r2], self[r1]
end
self
end
end

p "hello".gsub!(/ll/, 'l')
p "Hello world!".scramble!

I'm sure you can do this using only precluded modules, but it will be
quite a bit more involved.

An important part of cuts is also managing them and the methods in them.
Maybe you don't see this as important, but it is, especially when doing
AOP. Aspects can vary independently from the classes they applies to, and
they can even vary from class to class. Thus we need cuts that naturally
vary from class to class, and not modules that are about reusing the exact
same functionality.

Making management of the different layers possible for each class
separately is in our opinion important, and that is exactly why we started
on this, because for Matz' "def meth:pre ; end" syntax it is hard to do
because you can't get a handle on this method itself in a very Rubyesc
way. It's an error to postpone this, and first do #preclude and then build
a tacked on management system that won't be so Rubyesc. Cuts provide a
Rubyesc management system for the wrapper methods for a specific class.

Don't get me wrong though, I'm not opposed to having a #preclude method
too. But IMO the cut concept needs to live as well.

Peter


Trans

unread,
Oct 21, 2005, 2:42:57 PM10/21/05
to

Jacob Fugal wrote:
> How about this?
>
> Aspect.before( '*#save*', '*#delete*' ) do
> # advice
> end
>
> Implementation[1]:
>
> module Aspect
> def before( *cut_specifications, &advice )
> cut_specifications.each do |spec|
> unless PointCut === spec
> spec = PointCut.new( spec )
> end
> spec.joinpoints.each do |joinpoint|
> joinpoint.before &advice
> end
> end
> end
> end
>

[snip]

Nice "plunge into the foray" Jacob! I bet if you worked Binding into
the JointPoint you'd be even closer to what Alexandru is after. ( And
if you worked set_trace_func in there you'd be right on top of it, but
that would be SSSSLLLLOOOOWWWWW :)

Trans

unread,
Oct 21, 2005, 3:00:50 PM10/21/05
to
> (I speak only for myself, but I'll say our nonetheless)

I concur. "our" would be right.

Eric Mahurin

unread,
Oct 21, 2005, 3:32:27 PM10/21/05
to
--- Peter Vanbroekhoven <calam...@gmail.com> wrote:

> > The syntax is not consistent:
> >
> > class B meta-class of b
> > ------- ---------------
> > reopen class B ... end class <<b ... end
> > cut cut Bcut < B ... end cut <<b ... end
>
> Well, for the moment the patch does not allow this (I'm not
> claiming the
> patch is perfect, or even does all that we want it to do),
> but the full
> comparison would be this:
>
> open class B < A ... end class <<b ... end
> cut cut B < A ... end cut <<b ... end
>
> reopen class B ... end class <<b ... end
> 'recut' cut B ... end cut <<b ... end
>
> open' class B ... end
> cut' cut B ... end
>
> This seems consistent enough to me.
>
> What I've always found a pity though, is that the meta-class
> declaratiopn
> does not allow naming the meta-class, maybe like this:
>
> class Meta_b << b ; end

You are starting to touch on the inconsistency by asking for
the meta_class to be named like other classes are.

modifies
--------
class A < B A
cut A < B A, B
class <<b b.meta_class
cut <<b b.meta_class
class A A
cut A A, B ??

The meta_class vs. normal forms just don't seem consistent.

I have another idea that can be implemented in pure ruby using
flgr's 'evil.rb'. I'll send out another message about it.

Peter Vanbroekhoven

unread,
Oct 21, 2005, 4:09:09 PM10/21/05
to

No I'm not. My previous remarks have nothing to do with AOP. These were
side remarks. I was just saying that it would be nice to be able to name
it, not just within AOP, but in meta-programming in general. AOP involves
a lot of meta-programming, so it was only natural that I mention this
here. If it shows an inconsistency for AOP, it's there for subclassing
too.

> modifies
> --------
> class A < B A
> cut A < B A, B
> class <<b b.meta_class
> cut <<b b.meta_class
> class A A
> cut A A, B ??

One thing is that a cut indeed modifies B as well, while a subclass does
not. So if you're looking for differences there, well, they're bound to be
there because that's the idea.

cut <<b modifies the cut itself, as well as the meta_class it cuts, and
cut A indeed also modifies the cut class (in this case B). This should
complete your table above and makes it consistent again. That's if I
understand it correctly.

> The meta_class vs. normal forms just don't seem consistent.

But what's not consistent. You give tables, there is something different
(which is intentional, we wouldn't need cuts if they did the same as
classes, now would we?), but what's your point?

> I have another idea that can be implemented in pure ruby using
> flgr's 'evil.rb'. I'll send out another message about it.

Don't tell me it uses Object#become!

Peter


Dave Burt

unread,
Oct 22, 2005, 3:12:24 AM10/22/05
to
Trans:
> On the other hand cuts are in essence classes --transparent
> *subclasses* to be exact. While you do not instantiate them directly,
> they get instantiated as part of the class they cut.

I've just finished catching up on this thread (phew!) and you do make a good
point here. I still think, though, that a Cut is fully a Module, but only
partly a Class; it has a superclass but cannot be instantiated. I still
think that means Cut < Module and not Cut < Class.

> I think the real incongruency comes more from the fact that Class
> itself is a subclass of Module. It works okay, but conceptualy it is
> odd. And on occasion you have undef a method in Class that's been
> defined in Module. I think Matz even metions something liek this in his
> recent presentation. It think a better solution would come from having
> a "ClassKernel" module which is included in Module and Class, so they
> can stand on their own.

I'm don't think it's really an inconsistency in the current system, it just
makes Cut's place a little unclear.

> Finally, I think cuts are simliar to singleton_classes in that
> instantiating them is restricted.
> ...
> But I don't think there's any techincal reason they could not be. It's
> purposefully disallowed, I guess for conceptual reasons:

The comparison is interesting, and adds weight to your preference for class
over module, but it is a bit arbitrary in itself, and it doesn't mean
_another_ kind of class with no #new is OK.

> if (FL_TEST(super, FL_SINGLETON)) {
> rb_raise(rb_eTypeError, "can't make subclass of virtual class");
> ...
> Hey, this still says "virtual class"; _why doesn't his say eigenclass!?
> ;)

Another RCR? =)

Cheers,
Dave


itsm...@hotmail.com

unread,
Oct 22, 2005, 2:18:47 PM10/22/05
to
Does this also provide a quite general form of dependency injection,
very different in nature and weight compared to something like Needle?

Trans wrote:
> This is to "officially" announce an RCR that I posted to RCR archive
> two days ago. I realize the RCR itself is a bit dense and techincial,
> so (with thanks to ES) I thought it might be a good idea to provide a
> little summary and some examples of what it's all about and why it's a
> such a good approach to AOP for Ruby.
>
> You can read the RCR #321 <a
> href="http://www.rcrchive.net/rcr/show/321">here</a>.

Trans

unread,
Oct 22, 2005, 8:46:11 PM10/22/05
to

itsm...@hotmail.com wrote:
> Does this also provide a quite general form of dependency injection,
> very different in nature and weight compared to something like Needle?

Had to give this some thought. Mu immediate conjecture is that it must
since DI and AOP are closely related. But I'm no DI expert like Jim
Weirich. But in giving it some conosideration, I imagine there's not
much more to it than:

class App

def logger
nil # no logger available
end

end

cut AppContainer < App

def logger
Logger.new
end

end


T.

Christian Neukirchen

unread,
Oct 23, 2005, 6:25:05 AM10/23/05
to
"Trans" <tran...@gmail.com> writes:

Which will make you want "multiple-inheritance" for cutpoints. :-)

It's not that trivial, but it certainly can be used to implement DI.

> T.
--
Christian Neukirchen <chneuk...@gmail.com> http://chneukirchen.org


Trans

unread,
Oct 24, 2005, 4:42:03 PM10/24/05
to

Christian Neukirchen wrote:
> "Trans" <tran...@gmail.com> writes:
>
> > itsm...@hotmail.com wrote:
> >> Does this also provide a quite general form of dependency injection,
> >> very different in nature and weight compared to something like Needle?
> >
> > Had to give this some thought. Mu immediate conjecture is that it must
> > since DI and AOP are closely related. But I'm no DI expert like Jim
> > Weirich. But in giving it some conosideration, I imagine there's not
> > much more to it than:
> >
> > class App
> >
> > def logger
> > nil # no logger available
> > end
> >
> > end
> >
> > cut AppContainer < App
> >
> > def logger
> > Logger.new
> > end
> >
> > end
>
> Which will make you want "multiple-inheritance" for cutpoints. :-)

I thought about this some but I don't understand what you mean. How ill
it make you want MI? Aren't mixins enough?

> It's not that trivial, but it certainly can be used to implement DI.

I realize that it's a trivialized rendition, but could you provided
some pointers on improving?

Thanks,
T.

Daniel Schierbeck

unread,
Oct 25, 2005, 3:03:02 AM10/25/05
to

I can't see why there *shouldn't* be multi-inheritance for cuts, unless
you need to be able to find the exact class that's being cut by a
certain cut.

cut Kut < A, B, C
def initialize(*args, &block)
puts "ahoy, mateys! arrr!"
super
end
end


Cheers,
Daniel

Christian Neukirchen

unread,
Oct 25, 2005, 11:54:13 AM10/25/05
to
"Trans" <tran...@gmail.com> writes:

> Christian Neukirchen wrote:
>> "Trans" <tran...@gmail.com> writes:
>>
>> > itsm...@hotmail.com wrote:
>> >> Does this also provide a quite general form of dependency injection,
>> >> very different in nature and weight compared to something like Needle?
>> >
>> > Had to give this some thought. Mu immediate conjecture is that it must
>> > since DI and AOP are closely related. But I'm no DI expert like Jim
>> > Weirich. But in giving it some conosideration, I imagine there's not
>> > much more to it than:
>> >

>> Which will make you want "multiple-inheritance" for cutpoints. :-)
>
> I thought about this some but I don't understand what you mean. How ill
> it make you want MI? Aren't mixins enough?

Usually, you want to share a container and it's use between several
classes. With traits, this may be possible; I'm not sure about
mix-ins.

>> It's not that trivial, but it certainly can be used to implement DI.
>
> I realize that it's a trivialized rendition, but could you provided
> some pointers on improving?

Not offhand, sorry. But the "magic" behind Dissident could be done
with your cut points rather nicely.

> Thanks,

Trans

unread,
Oct 25, 2005, 6:16:11 PM10/25/05
to

Daniel Schierbeck wrote:
> I can't see why there *shouldn't* be multi-inheritance for cuts, unless
> you need to be able to find the exact class that's being cut by a
> certain cut.
>
> cut Kut < A, B, C
> def initialize(*args, &block)
> puts "ahoy, mateys! arrr!"
> super
> end
> end

That's a conceivable notation, but it's NOT multi-inheritance --we're
not creating a single class out of three. That's not what a cut does. A
cut is quite literally a *transparent subclass* so it simply augments
an existing class in a transparent way while maintaining a reasonable
amount of separation. Your example is really just a shortcut for doing
this three separate times, once for each class listed. The problem with
the syntax is that it is not Ruby-esque and we don't want to give the
false perception of multi-inhertiance which isn't there. Make sense?

So the way to do it is use a module and share that module. #preclude
works very well in this regard as long as don't plan on doing any fancy
dynamic inclusion to the module later on.

module Kut


def initialize(*args, &block)
puts "ahoy, mateys! arrr!"
super
end
end

A.preclude Kut
B.preclude Kut
C.preclude Kut

The other thing you can do, if you don't require a single handle to the
concern, is write an easy-peasy crosscut method (maybe not a bad thing
to have in general):

def crosscut( *classes, &blk )
classes.collect { |c| Cut.new(c,&blk) }
end

mycuts = crosscut( A,B,C ) do


def initialize(*args, &block)
puts "ahoy, mateys! arrr!"
super
end
end

No doubt one could go further and build a CrossCut class that holds the
code and a list of classes being cut. But that's framework stuff. As
I've said, the Cut is proposed to provide the strong foundation for
building all sorts of stuff like this.

T.

Ed Howland

unread,
Oct 26, 2005, 7:24:33 PM10/26/05
to
On 10/18/05, Trans <tran...@gmail.com> wrote:
> This is to "officially" announce an RCR that I posted to RCR archive
> two days ago. I realize the RCR itself is a bit dense and techincial,
> so (with thanks to ES) I thought it might be a good idea to provide a
> little summary and some examples of what it's all about and why it's a
> such a good approach to AOP for Ruby.
>

The concept seems clear to me. But I have an aditional question. Will
cuts be allowed on root classes that are themselves extruded from a
'C' extension? E.g. I don't really know if class IO is mostly C
extension stuff, but could a cut be applied to these class types?
Kernel? Object?

cut AspectIO < IO
def puts(*args)
# do something with the args
super
end
end

If I am understanding the syntax correctly. I don't know how the
internal hooking mechanism works here. But even if IO#puts is a
low-level C funtion, then super could just map to it, instead of the
normal ruby implementation of the method.

If so, then this could be a very powerful mechanism in Unit Testing:
(Again, forgive me if the syntax is wrong, here.)

class IOTest < Test::Unit::TestCase
@output = ''
cut AspectIO < IO
def puts(*args)
@output = args.to_s
super
end
end

def setup
@oldio = $stdio
$stdio = IO.new
end

def test_hello
puts "Hello world" # having the advantage of making @output
avail to assertions
# and spewing contents in the console.
assert_equals "Hello world", @output
end

def teardown
$stdio = @oldio
end
end

Is this acceptable in the RCR design? Was it already implied?

Thanks
Ed


Trans

unread,
Oct 26, 2005, 9:33:08 PM10/26/05
to
> Will cuts be allowed on root classes that are themselves extruded from a
> 'C' extension? E.g. I don't really know if class IO is mostly C
> extension stuff, but could a cut be applied to these class types?
> Kernel? Object?

Yes. It is applicable to any class (and any module via proxy-cut).

> Is this acceptable in the RCR design?

Ed, you're right on the money, Right On The Money.

> Was it already implied?

I believe we make a passing mention of AOP in general having applicable
to testing. But we offer no details in how cuts may be used for this.
Now you've lighted the way --and an interesing way at that. Very cool.

Thanks for sharing this.

T.

Ed Howland

unread,
Oct 27, 2005, 11:04:04 AM10/27/05
to
On 10/26/05, Trans <tran...@gmail.com> wrote:
>
> > Is this acceptable in the RCR design?
>
> Ed, you're right on the money, Right On The Money.
>
> > Was it already implied?
>
> I believe we make a passing mention of AOP in general having applicable
> to testing. But we offer no details in how cuts may be used for this.
> Now you've lighted the way --and an interesing way at that. Very cool.
>
> Thanks for sharing this.
>
> T.

No problem, just something I've been thinking about. Brian Button (and
others,) have said in testing, don't test the disk, and don't test the
I/O subsystem, don't test the OS, and don't test the built-in std
library. So, if the application is supposed to do these things, then
they are hard to test. Which has given rise to many diverse ways of
addressing this via mocking, using interfaces, dependancy injection
and so forth.

Ruby is nice, because you can mess about with its innards, and thus
get around some of these difficulties. Although, with TDDing and
refactoring, you shouldn't paint yourself into corners in the first
place. But for legacy code, this approach has some merit, IMO.

AOP strategies for unit testing are nothing new:
http://blogs.codehaus.org/people/vmassol/archives/000138_aop_unit_testing_example.html

Another potential use of AOP with testing is in fault injection:

cut IMHacker < Kernel
def exec(command, *args)
raise SecurityError "Caught ya, you lazy good-fer-nuthing low-life"
...
end
end

def test_catchem
assert_raise(SecurityError) { exec("cat /etc/passwd") }
end

.. where the exec call would really be buried in another class somewhere.

Any is there any prototypes of this available anywhere, or is it too
soon to ask that yet?
I'd vote for this, but RCRchive won't let me in.

Ed


itsm...@hotmail.com

unread,
Oct 27, 2005, 11:25:29 AM10/27/05
to

Ed Howland wrote:

> If so, then this could be a very powerful mechanism in Unit Testing:
> (Again, forgive me if the syntax is wrong, here.)

Yep, since DI is a very powerful mechanism for Unit Testing.

Except the cut-style allows you to do RealObjects, MockObjects, and
PartialMocks.

Ed Howland

unread,
Oct 27, 2005, 2:00:13 PM10/27/05
to
On 10/27/05, itsm...@hotmail.com <itsm...@hotmail.com> wrote:
>
> Yep, since DI is a very powerful mechanism for Unit Testing.

So you are saying that AOP (or cuts here for example,) can be used to create
DI where you don't already have it. Hmm.

#contrived
require 'collaborator'

class A
def initialize
@collab = Collaborator.new
end
# ...
end

# in TestCase
def setup
@mock_collab = MockCollab.new # or some DynamicMock library
end

cut NutherA < A
def initialize
@collab = @mock_collab # ignore super for the example
end
end

def test_add_mock_collab
a = A.new
assert_equals("expected", a.do_something_with_collab)
end

Is this what you were refering to with DI and Unit testing with AOP?

> Except the cut-style allows you to do RealObjects, MockObjects, and
> PartialMocks.

Can you expand on this a little? What are RealObjects (other than the
obvious) and PartialMocks? Aren't RealObjects just real objects that
are being mocked? How does the cut-style help?

Thanks
Ed


Trans

unread,
Oct 28, 2005, 12:26:11 PM10/28/05
to

Ed Howland wrote:
>
> No problem, just something I've been thinking about. Brian Button (and
> others,) have said in testing, don't test the disk, and don't test the
> I/O subsystem, don't test the OS, and don't test the built-in std
> library. So, if the application is supposed to do these things, then
> they are hard to test. Which has given rise to many diverse ways of
> addressing this via mocking, using interfaces, dependancy injection
> and so forth.

Which reminds me, I have some tests that are doing this that I need to
fix.

> Ruby is nice, because you can mess about with its innards, and thus
> get around some of these difficulties. Although, with TDDing and
> refactoring, you shouldn't paint yourself into corners in the first
> place. But for legacy code, this approach has some merit, IMO.
>
> AOP strategies for unit testing are nothing new:
> http://blogs.codehaus.org/people/vmassol/archives/000138_aop_unit_testing_example.html
>
> Another potential use of AOP with testing is in fault injection:
>
> cut IMHacker < Kernel
> def exec(command, *args)
> raise SecurityError "Caught ya, you lazy good-fer-nuthing low-life"
> ...
> end
> end

LOL :)

IOn this case though Kernel is module, so you can't cut it (cause you
can't sublcass it) But of course you could cut Object or use a module
and preclude:

module IMHacker


def exec(command, *args)
raise SecurityError "Caught ya, you lazy good-fer-nuthing
low-life"
...
end
end

Kernel.preclude IMhacker

> def test_catchem
> assert_raise(SecurityError) { exec("cat /etc/passwd") }
> end
>
> .. where the exec call would really be buried in another class somewhere.
>
> Any is there any prototypes of this available anywhere, or is it too
> soon to ask that yet?

Yes, though it doesn't do everything mentioned in the RCR, but it does
the basics:

http://rubyforge.org/frs/?group_id=137

> I'd vote for this, but RCRchive won't let me in.

Thanks. We've got a good favorable margin so it's okay, but I hope you
find out what's wrong.

T.

Ed Howland

unread,
Oct 28, 2005, 1:05:42 PM10/28/05
to
On 10/28/05, Trans <tran...@gmail.com> wrote:
>
> IOn this case though Kernel is module, so you can't cut it (cause you
> can't sublcass it) But of course you could cut Object or use a module
> and preclude:
>
> module IMHacker
> def exec(command, *args)
> raise SecurityError "Caught ya, you lazy good-fer-nuthing
> low-life"
> ...
> end
> end
> Kernel.preclude IMhacker

Definately have to find out more about precludes

>
> Yes, though it doesn't do everything mentioned in the RCR, but it does
> the basics:
>

Great! Is it downloadable? Where?

> http://rubyforge.org/frs/?group_id=137
>
> > I'd vote for this, but RCRchive won't let me in.
>
> Thanks. We've got a good favorable margin so it's okay, but I hope you
> find out what's wrong.
>

Thanks, dblack fixed my deficient brain. I strongly advocated, so you
are should over the top.

Ed


Trans

unread,
Oct 28, 2005, 1:18:22 PM10/28/05
to
Great! Is it downloadable? Where?

http://rubyforge.org/frs/?group_id=137

under 'cut (transparent subclass)' Use 3.0. It's a patch against Ruby
1.8.3 so you have to download Ruby source, apply the patch and compile
to try it out.

Right now it uses '__cut__' in place of 'cut' just to prevent a name
clash with a Tk method so that the testcases pass (not a big deal,
but..) Peter will look at adding #preclude support in a week or two.

T.

Kero

unread,
Nov 11, 2005, 10:05:25 AM11/11/05
to
> Just had Ruby 1.8.3 installed on our HP-UX box, and it seems to be
> really misbehaving... I'm trying to promote Ruby here but this is
> giving it bad press.
>
> For example, the following code
>
> #!/usr/local/bin/ruby
> p ARGV
> ARGV.each do |fname |
> puts "File: #{fname}"
> loop do
> break
> end
> end
>
> gives .....
>
>> xdump param
> ["param"]
> File: param
> /home/fcux_dev/tadb/bin/xdump:6: [BUG] Bus Error
> ruby 1.8.3 (2005-09-21) [hppa2.0w-hpux11.11]
> Abort(coredump)
>>
> And in fact, this error ([BUG] Bus Error - what is it ?) seems to pop up
> at the slightest provocation, although some relatively complex
> ruby code seems to run ok.
> I didn't do the installation myself, but I suspect that the HP-UX
> bundled C compiler was used to do the installation.
> Could that be the problem ?

Hardly.
I compiled ruby 1.8.1 or so succesfully with cc, just tried ruby 1.8.4-preview1.
Both work fine with your code above.

NB: I'm not the sysadmin, so I have to use ./configure --prefix=$HOME
you can try the same and see if you have better luck than your sysadmin.
Does miniruby have the same problem?

$ ruby -v
ruby 1.8.4 (2005-10-29) [hppa20.w-hpux11.11]
$ make test
test succeeded
$ make test-all
[some wsdl/iconv problem that I'll report on elsewhere.]

I don't think I managed to compile 1.8.1 with gcc,
haven't tried for 1.8.4-preview1.

Hth,
Kero.

0 new messages