# Advice Joining added to Cut-based AOP

**URL:** <https://www.ruby-forum.com/t/advice-joining-added-to-cut-based-aop/96087>\
**Category:** Ruby\
**Created:** [June 25, 2006, 9:15pm UTC](https://www.ruby-forum.com/t/advice-joining-added-to-cut-based-aop/96087 "2006-06-25T21:15:53Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![unknown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/4bbf92/32.png) [@unknown](https://www.ruby-forum.com/u/unknown)\
**Post date:** [June 25, 2006, 9:15pm UTC](https://www.ruby-forum.com/t/advice-joining-added-to-cut-based-aop/96087/1 "2006-06-25T21:15:53Z")

</div>

After some recent conversion on AOP on the list, I reviewing the  
Cut-based AOP proposal and found one area that needed some address,  
namely redirectly methods to their advice in a dyanamic and flexible  
fashion. So I modified part of the proposal and addeda new feature,  
which I think really strengthens the whole concept.

Advice Joining

Since advising multiple methods with a single advice is the common case  
of AOP, a convenient means of redirecting target methods to advice is  
essential. While it is trivial to define a method like the following  
Cut#redirect\_advice:

class Cut  
def redirect\_advice( h )  
c = h.collect { |k,v|  
“def #{k}(\*a,&b) #{v}(this,\*a, &b); end”  
}  
module\_eval c.join("\n")  
end  
end

cut A \< C  
redirect\_advice :f =\> :bracket, :g =\> :bracket  
def bracket( target )  
‘{’ + target.super + ‘}’  
end  
end

It is not sufficient for dealing with Ruby’s dynamicism. The above only  
handles methods defined in the target class at the moment the cut is  
defined. Complete AOP support requires the advice always stay in sync  
even under dynamic alteration of the targeted class. Ruby already  
provides means for this via the Module#method\_added hook, but robust  
use of this techinque is inconvenient at best. So a proper  
advice-oriented call is warrented, namely Cut#join.

cut A \< C  
join :f =\> :bracket, :g =\> :bracket  
def bracket( target )  
‘{’ + target.super + ‘}’  
end  
end

The Cut#join method would also accept wildcards.

cut A \< C  
join ‘\*’ =\> :bracket  
def bracket( target )  
‘{’ + target.super + ‘}’  
end  
end

The #join method provides the essential dynamic flexibility required of  
a robust Ruby AOP solution.

---

<div class="post-metadata">

**Author:** ![unknown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/4bbf92/32.png) [@unknown](https://www.ruby-forum.com/u/unknown)\
**Post date:** [June 25, 2006, 10:30pm UTC](https://www.ruby-forum.com/t/advice-joining-added-to-cut-based-aop/96087/2 "2006-06-25T22:30:15Z")

</div>

I would argue that is a bit more problematic than just applying the  
pointcuts onto the new methods.

If AOP were only about interception, that would be an all ok approach to  
just apply the cuts as soon as a new method appears.

however AOP != interception  
your aspect might rely on some mixed in state, and that state might be  
the result of a chain of actions done onto the subject.

if a new method is added to the subject, and you re-apply the cuts, you  
would also have to put the mixed in state for the aspect in a valid  
mode.

a very simple example:

lets pretend we have an aspect that cuts every getter in a class in  
order to apply “lazy load”.  
in order to do this, we need to mixin a state holder for the subject, so  
that we know in which state each property is, eg “not loaded” and  
“loaded”

when the subject is fresh, all the properties (attributes in ruby) might  
be marked as “not loaded”

and when you access a few of them they change their status to “loaded”

now lets assume that we add a new method(a getter method)

First of all, do we even want the lazy load cut to be applied to this  
method?  
the cut might have said “Cut all getters in the class” because when the  
cut was defined there were only a few properties in the class, and all  
of them were mapped to a DB.  
its highly unlikely that you would add a getter that is also mapped to  
the db at runtime.  
So the cut might be valid at one point but invalid once you add new  
methods.

but if we pretend that that was the case.  
what state should that property have in the LazyLoad mixin?  
loaded? , not loaded?

you might say “not loaded”  
but what if the getters member var had a value assigned to it to when  
the method was added, in that case maybe the getter should be treated as  
“loaded”?

and when and where should that state be applied?  
should the state mixin have some sort of mechanism to deal with new  
methods beeing added?

So the problem of added methods is not just about re-evaluating the  
cuts, you must also deal with state of the subject.

//Roger

---

<div class="post-metadata">

**Author:** ![unknown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/u/4bbf92/32.png) [@unknown](https://www.ruby-forum.com/u/unknown)\
**Post date:** [June 25, 2006, 11:45pm UTC](https://www.ruby-forum.com/t/advice-joining-added-to-cut-based-aop/96087/3 "2006-06-25T23:45:07Z")

</div>

Roger J. wrote:

> if a new method is added to the subject, and you re-apply the cuts, you  
> would also have to put the mixed in state for the aspect in a valid  
> mode.

AOP is not just interception, I agree with you. And the whole of the  
propsal certainly atests to that. The idea of cuts is not to supply a  
“total AOP framework” but just to provide a common and standardized  
foundation for doing AOP in Ruby. Going beyond that starts to push  
scope of what this proposal is about. One might argue for a more  
complete function, say:

cut A \< C  
pointcut( :someadvice ){ |jp| loaded?( jp.method ) …  
end

Sure, that can be done. You can do it in pure Ruby. The proposal  
doesn’t need to go into those details.

I also point out that Cut-based AOP is all about the 80/20 rule. There  
are things AOP it purposefully dosen’t address. For instance, local  
varaible assignments are not available joinpoints. But capabilities  
like that fall into that 20% range. Method interception on the other  
hand is 80% range. What happens when we shoot for the full 100% is we  
end up with a system that is too complex for general use and too  
inefficient in execution.

T.
