NAME

Overview - Aspects in Perl


DESCRIPTION

There isn't much in the way of documentaton, since at the moment I'm just toying around with ideas. I read about aspects on Xerox Parc's page and at aspectj.org and thought about how to implement aspects in Perl. The problem is, to do that effectively, you need support from the language and the compiler.

So I attempted a naive implementation, a proof-of-concept. Perl is hugely dynamic, everything's up for grabs. Including the flow of execution, if you use the Perl debugger API. So the idea is to hijack the debugger and 'make it do' aspects. Sure, this slows down things, but again, performance is not a consideration at this point. With Perl 6 still in the planning stadium, if aspects work and people like it, maybe it can at some point be made a part of the language itself.

The module closely follows AspectJ's idea of aspects. That is, there are

join points
well-defined points of execution such as entering a sub or exiting a sub,

pointcuts
operations and tests on sets of join points

advice
code associated with a pointcut, to be executed when that pointcut is matched in the course of execution.

To see how it all fits together, get the development version via CVS. You need Perl 5.6 for this to work. I've developed and tested it on Linux, so I can't guarantee if it works on other platforms, especially Windows. But so long as the Perl debugger works on a platform, it should be ok.

The module docs themselves are outdated, but go to the examples/ directory and run pointcut.pl, which will show you how it all works (from the outside).

A few words about the inner working: When using the Perl debugger, you get a chance to intercept subroutine calls via the DB::sub() subroutine. So there are two join points here already: a call join point occurs before executing the subroutine, and a return join point occurs afterwards. Now you might want something to happen when a subroutine main::mysub() is entered. To do so, you use calls() to define a pointcut using a call join point that matches if the name of the current sub is main::mysub(). Using advice(), you associate the code you want to execute when the pointcut matches.

All this is a bit abstract, so I suggest you look at examples/pointcut.pl, and follow the execution path into Aspect.pm (to set things up), the Pointcut modules (to define various types of and operations on pointcuts), and Devel/Aspect.pm (which does all the hard work of testing all defined pointcuts whenever a sub is entered or exited).

It is precisely this constant testing that slows things down (apart from the overhead of the Perl debugger itself); I've heard AspectJ implements this differently to avoid the overhead (some sort of preprocessing, supposedly). On the other hand, since Perl aspects are evaluated at runtime, it is conceivable that they can be changed at runtime (no idea why someone would want that, but that's what they thought about Quantum::Superpositions as well...).

In pointcut.pl, advice is defined explicitly, but later I want to define sets of advice (which will make up an 'aspect') in Perl modules that, when use()'d, produce the desired behavior. One idea is to force objects to be singletons by intercepting calls to its constructor. Or you can implement memoization (caching subroutine results, cf. Memoize.pm). Access control is another idea for an aspect that could be modularized.

Hopefully this has made it a little clearer as to what's going on; any comments or ideas are welcome.