PS: I’m not crawling back, I’m just waiting for you to refute all I’ve
been saying 
Haha! Y9ou knew I would 
Actually your example above could prove to be a useful application of
cflow. Suppose during compilation you’d have to do a number of tasks, and
each has a number of subtasks, and each of those too, etc. Suppose that
some of the tasks need to be run in a chroot environment, but you’d want
to run as little as possible in a chroot environment (say because that
minimizes security risks). You’d then have a main method called compile,
and a bunch of methods that either need to be wrapped in a chroot or not,
but you can’t make a clear separation in the call tree between the two
kinds of methods. I’ll give a simple example:
Sure, I think that can work. Try something like:
class Compiler
def compile
task1
task2
end
def task1:chroot
task2
task3
end
def task2:chroot
...
end
def task3
...
end
end
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
end
end
end
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
Anyway, ‘doer’ references the current method being executed. I think this
psuedo-notation is about right. Of course, the same effect, could also be
achieved explictly by setting a flag within the code itelf, say @chroot =
true, and coding each method to act on that flag. But then we miss the point
of AOP: seperation of concerns. Using AOP we can make the aspect independent
of class Compiler. So not only is it more flexible, but we could define it
sepatately and then reuse it on other classes.
For task1 we’d need to create the chroot environment. For task2 too, but
not when it is called from a method that already created a chroot env. For
task3 we need not create a chroot env, but we need to break one down when
called from a chrooted method. If we have a number of tasks like this, it
becomes cumbersome to code this in a consistent way. And thus we can use
AOP techniques. And to see whether we are in a chroot environment already,
we can use cflow. But we need to be able to limit it to the direct caller.
But suppose we have some real small tasks that don’t require a chroot
environment, but are too insignificant to break down and rebuild the
environment for. I remember saying that cflow is technically not required,
you can do the same with just wrappers. So maybe we should do it
explicitly in Ruby then. The only point of cflow is that if it’s a
recurring concept, it might be worth to have a separate notion of that in
Ruby. But what I don’t like about cflow is that unless we can find a much
completer notion to describe conditions based on control flow, using it
may cause troubles too. If the condition becomes more complex, then it’s
possible we can’t describe it anymore in cflow logic and thus we need to
make it explicit anyway. If it was explicit in the first place, we’d need
to change less. I don’t know if you’re still with me…
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.
BTW, about [ruby-talk:86785]… Correct me if I’m wrong, but the idea
there is that you want to have a wrap that is always the outermost wrap,
even if methods are redefined in subclasses, much like the problem of the
chroot environment you presented. But I think I still need to be convinced
of the use of wraps in such cases because it can easily be done with
current Ruby (using template patterns and alike). Granted, wrapping can do
the same thing in-place. But is that necessary? If a wrap is supposed to
stay in place, like in case of your chroot creation, it seems natural to
use something template-like. OK, that exposes more methods, like the
real_compile in my previous post, but that’s a more general problem of
visibility that’s cross-cutting. It’s the problem C++ tries to solve in a
clumsy way using friend classes, and what Matz tries to solve using
namespaces (but implementation-wise this is hard to do efficiently in a
dynamic language as Matz mentions on his slides). And actually with wraps
there’s the problem that wraps are anonymous (unless we use indicators, or
allow to index the wrap stack, which is definitely yuck), but using
template-like things and subroutines, that’s not a problem for all has a
name.
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’m not sure what your refering to with c friend classes and namespaces. Do
you mean instance variable visibility? Sorry if I’m just forgetting something
here. If this the case though, my take is that since wraps are implict they
should have access as if they were the same class. Perhaps outer wraps should
not and inner wraps should. Its just something that needs to be thought
through to come up with the best way. I think indicators are awesome by the
way :), but wrap indexing I agree is yuk, and I can only imagine it can do
nothing but cause weird ugly code hacks --nothing of really great use. But if
the indexing functionality is there it doesn’t so much matter as long as its
not something one HAS to deal with. I doubt it would get much use.
As for “neccessity”, this consideration is the very distinction between
explict/specific and implict/generic. It some cases the former is a must. In
fact the core of any program is explict, but the more one can generalize, the
more flexible, powerful and reusable are the solutions. I think one can see
it clearly if they’ve seen something like my GUI wrapper (despit the hack
that it is to achieve a current effect of wrapping) It really is quite
something to take an existing class and without touching a lick of code in
it, give it a GUI interface.
I’m just thinking aloud now, after reading up on AspectJ stuff. What
bothers me is that while reading the AspectJ stuff again, my reaction is
continually “so what, we can do that in Ruby already”. (I learned Ruby
after I learned about AspectJ.) The first picture they show in their talks
is a schematic representation of the lines of code in the different source
files of the apache web server code. They show that XML parsing code is
located in 1 file. They show that URL pattern matching code is only in two
files (because it’s a class and it’s subclass). But then logging is spread
all over the place. But then I say to myself that we in Ruby don’t have
such a problem. We are not forced to place the code of one class or module
by itself in one file. So we can perfectly move all the code concerned
with logging into one file. We can even make it generic so we don’t need
to write the same code over and over again. This shows again that Matz
wasn’t born yesterday. A class-based source file system forces you to put
all the code related to manipulating the same bit of data in one file,
even if code has parts that are about completely different concerns. Ruby
allows you to also split code based on the different concerns. If you
combine that thought with the idea of mix-ins (which the AspectJ guys try
to do using inter-class declarations, aka “open classes”), Ruby seems to
have more advantages than AspectJ will ever have.
I agree, Ruby has it over Java by a long shot – I am sometimes dumb-struck
that Java is so popular. Although I understand too, because I think Ruby
still has some maturing to do. But nonethess we can do many things with Ruby
that runs circles around Java. But to me that also means, with the addition
of good AOP fetures, Ruby will be even that much more beyond anything else
out there. In fact I think that the features we are now discussing, are so
fundementally mind-blowing once you start to understand thier power, that
combined with already amazing abilities of Ruby, this could become the one of
the things that really distinguishes Ruby from the the rest of pack --the
thing that will draw people to Ruby over other language choices. Do you know
what I mean? I mean really, AOP as easy as this? My god, It’s frig’n
incredible!!! Okay, I’m getting a little excited 
I don’t know if you see where I’m going. I don’t know if I see where I’m
going. But my conclusion seems to be that for internal wraps, we make
things more complicated by using wraps, rather than solve things. What we
seem to struggle with are things like the order of the wraps, removing
wraps, redefining wraps, etc, and these seem really hard when there are
wraps, but not when we’d use things like templates and subroutines etc
because then we already have explicit power to manipulate all of that.
I don’t think these are so much a struggle. For the most part I see how it can
be done. Much of the difficulty I think is fitting it into Ruby’s syntax
without too much “back breaking”. Also, you think its a tough coming up with
a good notation for removing wraps? Try removing 10,000 explict wraps from a
1,000,000 lines of code. 
However I do believe there is use in what we call external wraps, which
are really just hooks that get called when another method gets called, but
are not part of the intrinsic functionality of the method they wrap. The
gain there is that they are really invisible to the rest of the program,
only they know they are there. And for those wraps, things like the order
of the wraps in the stack doesn’t matter or removal on prime method
redefinition. But I feel that for intrinsic wraps we seem to be using the
wrong mechanism. It seems to take away explicit control, and we are now
looking for a way to give it back. If you know what I mean.
On the contrary, but I think I’ve explained it enough in the above. Right off
the bat my GUI interface would not be possible, and truth be told, we are
already doing this kind of thing quite often by aliasing methods and then
redefining them with call backs to the original. Worse, when this is done
genericlly we end up with a bunch of was_meth clutter. So inner wraps are
already here, but we need a clean and powerful way to do it right.
Maybe a final note… There are some features AspectJ has that we don’t
have in Ruby (or at least that I know of). In AspectJ a method can be
called when a variable is read/assigned (easy for a compiled language).
Also exception handlers are join points. Note that we could add hooks
there, but not without the hooked ones explicitly providing that
possiblity.
I think the latter can already be done actually. Well, I may be wrong about
that, but its close b/c error classes are/can be instantiated, which means
you can hook into the initialize method. As for the former, you’re right,
ther are no callback methods for assignment, there has been talk of this and
we may one day see it, but it would probably be too much overhead. I think
localizing instance variables will be good enough though, because you can
wrap accessor methods.
T.
PPS: Sorry for rambling on for so many kilobytes
Don’t be silly, that’s what kilobytes were made for! 
···
On Tuesday 09 December 2003 01:05 am, Peter wrote: