From: Peter Date: 2003-12-12T12:40:37+09:00 Subject: Re: Underpinnings of Method Wrapping > They do make sense, very good sense. And you make a good point. The problem is > that each class is linked to the next, not each method. So overcoming the > inefficiencies of picture #1 may prove a bit difficult. If no other way to > circumvent presents itself, and assuming it is a signifficant performance > loss, it may mean that the way inheritence currently works in Ruby needs to > be improved to allow greater granularity, and thus work on a method by method > basis rather than class by class. I know. In a compiled language, the overhead of searching for the class or superclass with the appropriate method is at compile-time, while in Ruby you need to do the search at run-time because of its dynamism. I don't know how much the Ruby interpreter optimizes or can omtimize. Only it seemed to get worse when wraps were done by adding singleton classes, but that depends on how popular wraps will be. And whether the 90-10 rule applies to wraps as well. > Clearly I have ;-) But please, no cracks on the spelling. I dispise it. And if > I had my way, id prbly typ lk ths. No cracks, promised. They were just congrats :-) > Exactly! That's exactly what I've been trying to convey. And is also exactly > what tuned me on to my def syntax. (Guess I don't explain myself very well. > Oh well.) Nonetheless, I'm glad you have envisoned this way of looking at it. > It really made wraps make sense to me. And I see what you're saying about > super. So, like subclasses, wrap should be perisistent, and it takes an > explict undef to flush them, as they can always be cricumvented by not using > super, but the may be gained back. OK, but my impression was that you wanted those singletons to be "implicit", that the singleton classes would make up the implementation and wouldn't show up explicitly. class Test def m1 ... end def m2 ... end end wrapper TestWrap def m1 ... super ... end def m2 ... # no super end end class Test wrap TestWrap end If we have a situation like this, a wrap is always defined in a wrapper class. Redefining a wrap happens in the wrapper class. The wrapper is explicitly like a subclass (explicit to the programmer that is), and so we really can use the same syntax as we've always done in Ruby. Redefining the primary method happens in Test, redefining a wrap happens in TestWrap. So to the programmer it is no different from using subclassing, except that anyone using Test unknowingly also uses TestWrap. That's what I meant. Doesn't that kinda solve the syntax problem? A wrapper could still refrain from calling super, but that is its constitutional right (we should create a constitution for wraps). But everything is explicit (since subclassing is explicit, and redefining methods is), and it is consistent with current Ruby. That's what I was hoping to tell you. Oh, and we could give a wrapper (say it gets Wrapper as class, like a class has Class as class and a module has Module as class) a callback method "wrappee_changed" that is called when the class (or wrapper) that is wrapped changes such that it can take the right decision. We can give Wrapper a private method set_flush(boolean) that sets default behavior of "wrappee_changed", but you can redefine it and choose your own behavior. That is possible if the layers are explicitly offered to the programmer. But I get the impression that I had the wrong impression and that you already thought of all of this... And to go a bit further, I think with inner wraps (as in the ones that get flushed when the primary methods is redefined) the "unknowingly" aspect is less useful. There's the primary method, then the inner wraps, and then the outer wraps, and I get the feeling that the outermost inner wrap is what is seen on the outside, and the outer wraps are invisible. And then inner wraps is much like subclassing since the collection of inner wraps and primary method really make up the whole of the method. And besides this distinction between inner and outer wraps, there is also the kind of wrap that is used for chaining hooks, like method_missing, inherited, method_added, ... but that feels like a different kind of application of wraps altogether. It feels more method based and making a complete layer for it seems overkill. > > class A {} > > class B {} > > > > aspect BiDirLinkAB { > > > > private A B.linkToA = null; > > // a link to B in class A, but class A can't see 'linkToA' > > private B A.linkToB = null; > > // a link to A in class B, but class B can't see 'linkToB' > > > > public void A.linkTo(B obj) { > > if (linkToB) linkToB.linkToA = null; > > // Note that although this method goes into class A, it can access > > // linkToA in class B > > linkToB = obj; > > if (obj.linkToA) obj.linkToA.linkToB = null; > > obj.linkToA = this; > > } > > > > public void B.linkTo(A obj) { > > // analogous > > } > > > > public B A.getLinkToB() { > > return linkToB; > > } > > > > public A B.getLinkToA() { > > return linkToA; > > } > > > > } > > > > There's no wrapping, but it's cross-cutting since you have one entity (the > > aspect) containing the code for maintaining data in two separate classes. > > Sorry, my java skills stink. As best I can make out, you're talking about a > variable or method(?) particular to a class, but not visible to the class, > but rather to the aspect that defines it. Sort of like a hash with an implied > self.class for an index. > > @@private_to_aspect[self.class] > > If that about right? I suck at AspectJ lingo too. Java should still be doable. I just used AspectJ lingo (or my version of it) because that is existing syntax, in Ruby it would be speculative. But I don't really know what you mean with the hash. My first idea would be to say that it is like a hash indexed by the objects that are linked. Wait, let me put it this way. Without aspects, a bidirectional link would look like this: class A def link2B=(objB) @link2B = objB # and other stuff to keep the links consistent end end class B def link2A=(objA) @link2A = objA # and other stuff to keep the links consistent end end Maintaining those links (i.e., if object1 points to object2, then object2 should also point to object1) is a cross-cutting concern (it involves data in two classes), we would like to make it an aspect. Then the aspect could declare @link2B and @link2A to be private to the aspect, such that both link2B= and @link2A can access them because they belong to the aspect, but other methods in class A and B can't. The only way to move @link2B and @link2A to the module containing the aspect methods, would be by introducing two hashes @@link2A and @@link2B that respectively map object of class B to objects of class B and vice versa. > I think its b/c persistence is a sticking point at the moment. Perhaps we > should give some focus to this matter once again, starting with a review of > what we've figured out about it thus far. Think I'll add some subsection note > pages to the wiki page, this issue will be the first. Work for you? OK. But first I'd want your opinion on what I mentioned above about introducing wrappers next to modules and classes. Wrappers would inherit from modules just like classes BTW. But I'll work it out and append it to the examples I currently have. I'll see how far I get by tomorrow evening, if it's in a decent state, I'll send it to you. Otherwise it's for after the weekend. I'm currently using the RD format (and using the cool rubygarden wiki CSS in the generated html :-) > Thanks. Is interesting, but does seem like a difficult undertaking. I can see > why it is still research. Yes, it is easy to see why wrapping has catched on already unlike the things about optimization. But I think general code weaving holds some relation to code generation. It's bed time for /me now. Peter PS: I wanted to do something like this today, to provide for the future addition of indicators, but it didn't work: class Test def test instance_methods(true).each do |m, i = ''| if i =~ /silly_indicator/ ... end end end end Apparently blocks can't have default values for arguments...