From: Peter Date: 2003-12-10T13:16:45+09:00 Subject: Re: Underpinnings of Method Wrapping > QUICK SIDE NOTE: might be nice to have something for all those dang ends. How > about end_____end, with as many underscore (2 or more) as needed: > > Compiler.aspect do |meth| > if meth.tag==:chroot > meth.wrap do > if doer.cflow_ancestors.any? {|a| a.tag==:chroot} > super > else > chroot_evironment do > super > end_____end Actually counting consecutive underscores is hard. On my screen they make up one long line. > cflow logic is certainly a different way of thinking, but I don't really see > how cflow logic would become so complex that you'd want to go back to > explicts. It's essentially the same logic, actually, just applied > differently. In fact I think one will find that the ease of managing such > aspects are on an order of magnitude greater than explictly doing so. I don;t > see cflow being the the essential part of AOP, but it is another useful part > of it. Agreed, cflow is not *the* essential part of AOP. But I think I should make my example more concrete to show the complexity of cflow logic (although maybe it may be a bit contrived, but I hope you get the point). class Compiler def compile:no_chroot task1 task2 end def task1:chroot # do some stuff task2 task3 # some other stuff end def task2:chroot end def task3:no_chroot # do some stuff task4 # do some other stuff end def task4:whatever task5 end def task5:chroot end end I used indicators to indicate whether a method needs chroot, or doesn't want it, or it doesn't matter (if the task it performs is so small that it is overhead to change the environment and then put it back). What your wrapper then needs to do is create a chroot env for methods with a 'chroot' indicator if it wasn't there yet, and destroy the chroot env for a method with the 'no_chroot' indicator, if the env was there. So basically, in terms of cflow, you need to create the chroot env when you are in the cflow of a method m1 with the chroot indicator, and when there is no other method m2 in the cflow of m1, unless there's another method m3 in the cflow of m2 that has the chroot indicator, etc. OK, I'm exagerating, but you need to be able to say that there exists a method m1:chroot in whose cflow we are and for which no method m2:no_chroot exists in its cflow and in whose cflow we are too. You can't even say that in AspectJ BTW. But if I do it myself explicitly, I'd just add a variable to the Compile class that keeps track of whether we are in a chroot environment or not, and have my wraps use that information and change environment if needed and set that variable accordingly. Much easier, and much harder to break by extensions. The alternative is to change the subdivision of the tasks so that we can group chrooted tasked, but since chrooting is another concern, we don't want that governing the way we subdivide the tasks. > Well, sort-of, in 86785 I was showing how we might mixin singletons in a class > definable way, which is the essence of wrapping. Its not that they are outer > or inner per se; I wasn't thinking about that at the time, and is something > additional to take into consideration (currently they would indeed be outer > though). We can already define mixin singletons in an object definable way > using #extend. You may have read about that in a couple of my recent posts on > the matter (87408 is good starting point in the thread). I agree that there are already features present in the Ruby language that allow us to do wrapping-like things. But if I understand well that's mostly based on subclassing (defining singletons comes down to defining singleton classes implicitly). As for my mention of friend classes and namespaces... Currently in Ruby there is class-based access control for methods and variables. For the former it can be changed (public/private/protected), for the latter it is fixed (until @var and @_var come along that give some control). But since aspects are cutting across classes, we'd naturally need something more than class-based access control. Actually a simple example of a cross-cutting concern is a bidirectional link between two objects. Keeping those links consistent is one concern, but if the objects involved are of different class, this concern involves multiple classes. An aspect could keep track of the links and make sure they are always consistent. In AspectJ you could sneak in some variables to keep the links in the respective classes, but they are private to the aspect and can't be accessed from those classes. That's logical because then any operations involving the link are performed by methods that the aspect offers and consistency is guaranteed. Of course the notion of friend classes is too limited in this case, but it allows to change access control. Namespaces do that too in a sense. But to get back to my previous mail; I think the point I was trying to convey is as follows. When we look at outer wraps, we see that they are really just hooks. You can hook em, unhook em, and nobody will ever notice a thing except you yourself. That's clean separation of concerns, and that's what AspectJ does best. Examples are security, profiling, tracing, logging, GUI observers, pre/postcondition checking, keeping dirty bits when objects on screen are moved, error logging, invariant checking... They are best done by using hooks (or outer wraps). But then inner wraps. As you've pointed out, a primary method and its wraps are really one whole. If a wrap is removed, then the method will change functionality. Adding an inner wrap or removing one is much more noticeable. Actually they kind of behave like a method and the helper methods (or what I called subroutines by lack of a better term) it calls, or like a method calling the same method in a super class. They add layers of extra functionality. To me it feels like that is what class hierarchies were invented for, or the hierarchy in a method call graph. Maybe what I need is a simple example of inner wraps (that I could in no way classify as an outer wrap, because I think our notions of that are slightly different) and that clearly demonstrates its importance in separating concerns in the sense that it does it better than current Ruby. Then we could discuss something more concrete. Or maybe I should wait until your RCR has been updated. I know I am overly sceptical now, but maybe that's because some things are getting clearer, and other things getting fuzzier. Peter