From: "trans. (T. Onoma)" Date: 2004-11-28T10:29:53+09:00 Subject: The likes of AOP (1 of 2) I've been doing some thinking on AOP ... There are three fundematnal implementations types of AOP: Static Weaving, Dynamic Weaving and Dynamic Triggering (Event-based). So how do these differ? Static weaving simply looks at source and based on it determines where to add (and possibly remove) code.[1] Thus it is limited to the program definition and cannot alter the program based on any execution state. This works okay for static languages like C, but would never do for a dynamic language like Ruby simply b/c the code itself can change on the fly. That's where Dynamic Weaving comes in. It is the same as Static Weaving except that it can react to dynamic code changes; it is thus an AOP necessity for any dynamic language like Ruby. But that is really all it is --it simply adjusts for weaves based on code changes, NOT state changes. While it is possible for Dynamic Weaving to dynamically add and (potentially remove) weaves based on state changes, doing so is exceedingly hackish --it is much easier to check for state changes within permanently weaved advice. To properly aspect code based on state one must move to full-fledged Dynamic Event-based Triggering AOP. In my experimentation with "legacy" AOP implementations like that of AspectJ and AspectR, I've come to the conclusion that they are of only minor use in a language as dynamic as Ruby. With a good mechanism for weaving, like `class cuts`, reentrant classes, and a good set of callbacks, one can do everything AspectJ, or like lib, can do in a way generally more fitting the actual problem. Consider: class AnAspect < Aspect def pointcut( jp ) :advice if jp.klass.name =~ /^T/ && jp.meth.to_s =~ /^t/ end def advice(*args) puts "Log #{target.meth} args.inspect" end end vs. class Class def method_added( meth ) if self.name =~ /^T/ && meth.to_s =~ /^t/ Cut.new( self ).send(:define_method, meth) do |*args| puts "Log #{meth} args.inspect" end end end end The former "traditional" AspectJ-esque way is a bit easier to read, which is nice, but only a bit. Any implementation of an AspectJ-like lib for Ruby will essentially translate the former into something akin to the later (albiet a more efficient implementation [2]) So it does not strike me as largely significant to design yet another YAAR (Yet Another Aspect lib for Ruby) --on the whole the matter is fairly straight forward. I need to take a break. I will be following this up with some more thoughts on Event-based AOP. T. == FOOTNOTES == 1 An interesting thought is whether it could weave code based on its own previous weaves --and thus the potential for an infinite aspecting. Ouch. 2 Peter you might notice why I used the #clearcut method in dynaop.rb from the above example. With it I was able to advise methods individually while minimizing the number of Cuts added to a class (fro efficiency). This makes me think that an excellent support method for cuts would be exactly that: Class.define_cut_method( sym ) { |*args| ... } This would define a method in the nearest cut of class lacking the method #sym, or create a new cut for if need be. Then the above implmentation becomes simply: class Class def method_added( meth ) if self.name =~ /^T/ && meth.to_s =~ /^t/ self.define_cut_method( meth ) do |*args| puts "Log #{meth} args.inspect" end end end end And perhaps a better name for that method is simply #wrap ;)