Hi Tom,

> Yep. I recall. Template Design Pattern. Didn't know that it had a name. Well,
> it's what I did, as I don't think there is better way to do it at this point.
> Thanks Peter.

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:

  def compile # needs no chroot
    task1
    task2
  end

  def task1 # needs a chroot
    task2
    task3
  end

  def task2 # needs a chroot
    ...
  end

  def task3 # needs no chroot
    ...
  end

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...

> It's all good. I have lots of stuff on my plate right now. I'll just keep
> touching back on this as it developes in my mind. Have started some rework on
> the wiki page.

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.

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 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.

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.

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.

Peter

PS: I'm not crawling back, I'm just waiting for you to refute all I've
been saying :-)

PPS: Sorry for rambling on for so many kilobytes