[ANN] [RCR] Cut-based AOP

T

Trans

Eric said:
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.
 
A

Alexandru Popescu

#: Trans changed the world a bit at a time by saying on 10/20/2005 6:36 PM :#
Hi--



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.
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.


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.
Sorry, I do not full understanding. We do address crosscutting, and OO
nature.


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?

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.

/alex
 
E

Eric Mahurin

--- Trans said:
Eric Mahurin wrote:
=20
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.
=20
Other then that I'm not sure if there is anything *undoable*.

So, let's start with the simple preclude/wrap module concept.=20
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=20
http://mail.yahoo.com=20
 
P

Peter Vanbroekhoven

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
 
T

Trans

Alexandru said:
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.
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.
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.
 
A

Alexandru Popescu

Most probably my comments are missinterpretted. I am not trying to argue =
the value behind the RCR.=20
Neither I contradict it's power. I am just trying to point that it is mis=
sing important features.=20
Once we agree on this, the discussion may proove fruitful. Otherwise, the=
re is no reason to continue it.

I surely would like to write my own one. As said I am not ruby expert, an=
d when time back I was=20
asking for the community help (and should I mention that I asked your per=
sonal help?) on this matter=20
I got some form of refusal in the form: you can do this trick and that tr=
ick and you will have=20
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 :#
tricks for making it work.
=20
What do you want to say? There are a number of Dependency Injection
frameworks being worked on for Ruby,=20

I was not talking about innexistent good frameworks in Ruby. I was talkin=
g about the principles of a=20
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.
=20
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".
=20
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.
=20

I have still to disagree with this percentages. But for the moment, it is=
not so important.
I have said it too many times: I am not a Ruby dev, so this one line o= f code pointcut support is not
clear to me. Can you help me out? I want a pointcut that will match al= l calls to a db operation
method so that I can crosscut the transaction concerns.
=20
Sincere? Just this "wee" problem? A little scarse on detail? Let's not
make it too easy on me now! But hey, no problem! ;)
=20
class JoinPoint
attr_reader :klass, method
def initialize( klass, meth )
@klass =3D klass
@method =3D method.to_s
end
end
=20
def pointcut(&pcut)
ObjectSpace.each_object(Module).each { |base|
adv =3D {}
base.instance_methods(false).each{ |m|
adv[m] =3D 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 =3D mod.new do
adv.each { |a,p| define_method(a,&p) }
end
base.module_eval { preclude aspect }
end
}
end
=20
pointcut do |jp|
if jp.method =3D~ /^database/
lambda{ |*args| DB.transaction{ super } }
end
end
=20
Okay took about ten minutes....okay, fifteen. Please excuse any
simpleton bugs, I really don't feel like testing it. You get the
piture.
=20


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=20
'database'. And I am wondering where is the modularity of this piece of c=
ode. How can I reuse it?=20
(copy and paste?)

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

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

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

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

m flow; the others are not.
=20
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.
=20
=20
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.
=20
e) points in program execution.
=20
Oh sure you do! My MethodProbe would eat it up :)=20
=20
T.
=20
=20
=20

Not sure what is MethodProbe. What I am sure is that in the long run an i=
nstabel pointcut system=20
that exposes such `volatile=B4 infos will not pay back the effort.

cheers,

=2E/alex
 
T

Trans

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.
 
T

Trans

Alexandru said:
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.
 
A

Alexandru Popescu

#: Trans changed the world a bit at a time by saying on 10/21/2005 1:16 AM :#
I have already agreed. We are not promising the world. Like I said we
focused on most common potential uses.


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.
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.

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,

/alex
 
R

Ryan Leavengood

Probably it would be interesting to start doing the cuts and see how we c= an 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
 
A

Alexandru Popescu

#: Ryan Leavengood changed the world a bit at a time by saying on 10/21/2005 6:35 AM :#
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

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,

/alex
 
D

Daniel Schierbeck

Trans said:
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.

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
 
C

Christophe Grandsire

Selon Daniel Schierbeck said:
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 sens=
e*. 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 natur=
al 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 sub=
classes
really was the thing that made me understand their functionality, and I f=
eel >
goes against that definition.

I understand why you are proposing such a syntax. I just feel people woul=
d get
the wrong impression from it.
--
Christophe Grandsire.

http://rainbow.conlang.free.fr

It takes a straight mind to create a twisted conlang.
 
E

Eric Mahurin

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

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 =3D B1.new
b1.foo # =3D> "B"

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

# super : A.instance_method:)foo).bind(self).call
class B1
def foo
"[" + super + "]"
end
end
b1.foo # =3D> "[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 # =3D> ""

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



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

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


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?



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

Eric Mahurin

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.=20
#preclude would just be another method so it shouldn't cause
compatibility issues like "cut".



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

Trans

Eric said:
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.
 
T

Trans

Sorry for the delay steve. Mnay questions...
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.
 
P

Peter Vanbroekhoven

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.

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
 
J

Jacob Fugal

class TransactionAspect < AOP::Aspect
pointcut: transactionalMethod =3D> "*#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 =3D=3D=3D spec
spec =3D 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 =3D []
cuts.each do |cut|
module_pattern, method_pattern =3D cut.split /#/
module_pattern =3D Regexp.new /^#{module_pattern}$/
method_pattern =3D Regexp.new /^#{method_pattern}$/
ObjectSpace.each_object(Module).each do |base|
if module_pattern.match( base.to_s )
adv =3D {}
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 =3D klass
@method =3D meth
end

def before( &advice )
if Class =3D=3D=3D @klass
Cut.new( @klass ) do
define_method @method.to_s &advice
end
else
aspect =3D 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.
 
P

Peter Vanbroekhoven

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

easy AOP right now using evil.rb 2
RCR 13 0
RCR for Range.rand 0
AOP bigger picture 3
The likes of AOP (1 of 2) 1
ideas for an RCR: variable locality 16
aop in ruby 2
No Thing Here vs Uninitialized and RCR 303 21

Members online

Forum statistics

Threads
473,982
Messages
2,570,190
Members
46,736
Latest member
zacharyharris

Latest Threads

Top