From: Peter Date: 2003-11-30T23:57:01+09:00 Subject: Re: Underpinnings of Method Wrapping > How would they know? ;-) The all-seeing eye? I believe they got feedback from a number of large projects that used AspectJ. > I'm had some varying thoughts on this. But I think I've come to a good > solution. First let me point out that, although unmentioned in my RCR, I'm > all for pre and post, and actually, I'm now in favor of dblack's suggestion > of simply using pre and post as keywords [yes, db, bygones &c.] b/c they are > ONLY for "meta-tasks" and can't get invovled in the underlying exectution; so > in this manner they are quite distinct from def. In other words, defs "get in > line" while pres and posts "hang about", if you take my meaning. In light of > this, it seems appropriate for redef to flush the wrap stack, but all pre's > and post's still remain. So we have proper seperation of these concerns: pre > and post for extrinsic, def wrap for intrinsic. I like the proper separation, but why pre and post for extrinsic and def wrap for intrinsic? > Is it very expensive? ameth.cflow.cflow... hmmm, I guess your right, if your > looking for a method that could be anywhere up the reference list. Although I > think in practice the list will only get so long. (And shortcutted for > recursive calls). But I definitely see your point (though I think > Method#cflow would still have its uses). Yup, the call stack in general is pretty small, except in case of a recursive algorithm. But mutually recursive methods complicate things a bit for any shortcut ;-) > I noticed right away that you were using my syntax :-) I've heard so many > people say how ridiculous such a syntax is (funny that they keep mentioning > it), but right now I can tell you it feels completely natural --seeing the > defs come in order parallels their stacking order. Anyway... Agreed, but these are small examples. What if a primary method and its wraps are dispersed throughout the source code? > Definitely, and I'm certain we can achieve the same thing with module's and > their instance variables. Define a module containing aspect methods and the > module variables they need and apply as desired. Hell, we can even wrap the > aspect methods! :-) But one aspect adding advice to methods in more than one class is - though perfectly possible - more complicated, unless I'm overlooking something obvious. > Ah...but this is what the indicators are for. > > def eat:eating > end > > def gorge:eating > end > > def stuffyourface:eating > end > > We can aspect all the eating methods. ( no, i'm not hungry :-) Grand! Can we specify multiple indicators when calling multiple methods with different indicator demands? > But I'm getting ahead of myself. I need to explain the point. Lets take this > example: > > class Classic > def x > print "X" > end > end > c = Classic.new > def c.x > print "(" > super > print ")" > end > c.x; puts # => (X) > > We have created an object c, that has a method x, then we defined a singleton > also called x. The singleton effectively wraps the original method. This is > explained well in the Pickaxe. Check out page 246, Fig. 19.3. The diagram is > describe a couple pages back under Object-Specific Class; or you can surf > here: > > http://www.rubycentral.com/book/classes.html Ah, that kind of singletons... But it confuses me that you are calling the method the singleton. Isn't c the singleton, with its own singleton class in which the method x is put? > So then what happens if we try to add another singleton of the same name? > > def c.x > print "[" > super > print "]" > end > c.x; puts # => [X] > > Why didn't it wrap again? Let me quote the end of that Pickaxe section: > > "Ruby performs a slight optimization with these singleton classes. If an > object's klass reference already points to a singleton class, a new one will > not be created." > > Obviously when Matz created this, it didn't occur to him that unlimted > wrapping may be useful. He just saw that it was wasted overhead to have a > separate singleton class for each and every singleton method. But his > optimization had the above side effect --you can only define one layer. So I > went back and changed the optimization such that when a method of the same > name already exists in the singleton class, a new singleton class (metaclass > in the code) is created. So my version of Ruby instead does the following: > > def c.x > print "[" > super > print "]" > end > c.x; puts # => [(X)] > > That's all there was to it, and it serves as the perfect starting point/basis > for building all the rest of the AOP features. OK, but my reading of singletons was always as follows. When a singleton is created, it gets its own singleton class that is a subclass of the original class. The added method goes in the singleton class. If I define c.x, it is put in the singleton class, and super is a call to the method in its superclass, in this case Classic. Defining another c.x just redefines the method in the singleton class, and super still calls Classic#x. This would be consistent with explicitly creating the singleton class, say Classic_c, and redefining Classic_c#x. In this interpretation, Matz's optimization is completely valid. But it could also be that I interpreted it that way because that's consistent with the optimization... Peter