The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Aspect Ideas - new ideas for aspects-oriented Perl

DESCRIPTION

Distribution Ideas

Cookbook recipes
Benchmark suite
Comprehensive tests

The following sections outline ideas for modular aspects, for new types of join points, and for new types of pointcuts. There are also some general ideas.

Modular Aspect Ideas

Development Aspects

Development aspects are aspects that are useful in the development of software. Because aspect behavior can be enabled and disabled easily, you can cleanly separate the product from the development aids. When you are finished, you can remove the aspects altogether leaving only the product. That way, the development tools are not included in the finished product, but can easily be reenabled for further development.

An obvious example of a development aspect is tracing the program flow. See Aspect::Trace.

Design-by-contract

Implement design-by-contract pre- and postconditions using aspects, cf. Class::Contract.

Default Variable I/O

Per Sub::Underscore.

This sets up a wrapper for a sub that takes a scalar as an argument and returns a scalar. The wrapper calls the sub with $_ if no argument was given and puts the return value in $_ if the sub was called in void context.

An example:

    my $aspect = Aspect::UnderscoreContext->new('main::plus1');
    $aspect->enable;
    ...
    sub plus1 { $_[0] + 1 };
    plus1;  # now $_ has been incremented
Package Redirection

say you implemented a specialized version of the HTTP::Request object and want LWP to use that. But you don't want to change the LWP code, as that would mean branching. And sending a patch to Gisle isn't a good idea either, because your new class is very specialized, so the patch might get rejected. So you set up advice that any calls to package HTTP::Request should be redirected to your new class.

Load-balancing

have the same code run on different boxes or in different processes or threads and provide mod_backhand-like functionality via aspects.

Advertising

A stupid use of include join points:

    advice(includes(qr/./, \&aspect_ad))

might say "Thank you for using CGI.pm" (get the module name via context) or "Brought to you by Aspects".

Automatically done only once per module, as each module is use()d only once, but do that with op join points as well: print an ad the first time only via $seen{$op}++.

Testing

Aspects useful for CPANTS

Timeout

Aspect to provide timeout to subs via alarm().

Tainting

Aspect to taint and untaint args and return values of subroutines.

Authentication Aspect

Users and groups; give rwx access to variables and subroutines. Via aspects, you have external control over permissions. When doing something that requires permission, either ask for authorization (provided by a keychain?) or allow or deny, like Apache does.

Once-only Aspects

Run the advice code once, then remove the aspect code.

Aspects checking arguments

An aspect could check the bounds of subroutine arguments and, if necessary, throw an exception or otherwise signal an error.

Join Point Ideas

Some ideas for new kinds of join points, that is, well-defined points during execution:

Include Join Point

Using coderef-in-@INC, you can intercept use() statements:

        BEGIN { unshift @INC, \&include_join_point }
        sub include_join_point {
                # process relevant advice
                # now decline so normal include handlers
                # can do their work

        }
Op Join Points

overload operations to raise op join points, e.g.:

        overload '+' => \&add_join_point;

        sub add_join_point {
                # process relevant advice
                # return a+b as normal
        }

This won't work if the package already overloads operations.

Import Join Points

by overriding or wrapping a package's import()

Destroy Join Points

by overriding or wrapping a package's DESTROY()

Phasic Join Points

by defining a BEGIN, INIT, CHECK, END handler for a package

Package-specfic Join Points

Packages (modules, classes) may define their own types of join points. For example, the Error module might define a Throw Join Point, a Catches Join Point, a Try Join Point and a Finally Join Point.

Classes that construct other classes (such as Class::MethodMaker or Class::Contract) could define a Field Get Join Point, a Field Set Join Point and a Constructor Join Point. A convenience Field Access Join Point could simply be defined as "either a Field Get Join Point or a Field Set Join Point". And there might be a Method Call Join Point and a Method Return Join Points. These class-related join points would also come in useful in Perl 6, which has special language support for classes (as opposed to non-OO modules).

These special join points must be able to influence the context passed to the advice code. For example, a Field Set Join Point would want to pass on the new value in the context (though in this case it can be gleaned by looking at the method's arguments).

Viewed this way, Perl signal handlers could be viewed as advice on Signal Join Points.

Pointcut Ideas

New pointcut designators

Using existing pointcut operators and logical operators you can create new pointcut designators.

Pointcut match efficiency
    pointcut p1 { $joinpt1 & $joinpt2 }
    pointcut p2 { $joinpt3 && $joinpt4 }
    pointcut p3 { $p1 | $p2 }

Cache eval results for join points and points cuts, so (as is the case with p3 above) each join point and pointcut is eval'd only once per advice.

cflow($x)

cflow() is a pointcut operator that matches any kind of join point where the call stack at run time matches the condition specified with the cflow() operator.

pkg($x)

matches join points of any kind (i.e., context isn't checked) where the currently executing package matches $x.

is_a($x)

matches join points of any kind (i.e., context isn't checked) where the currently executing package is-a (per Perl's @ISA hierarchy) $x.

calledby($x)

is like cflow() but looks at the direct caller only. That is, there is a match if the current sub's immediate caller matches $x.

Debugger Support

Debugger support for developing with aspects.

Debugger commands

Continue to next join point

Affected Join Points

List all join points affected by a pointcut.

Meta-aspects

An aspect to insert breakpoints or print other information when a join point is encountered.

Completely Random Ideas

Runtime (RT), coincides with program runtime. Define-time (DT), also happens at program runtime.

At DT, i.e., when an advice is defined, the advice's pointcut is tested against each join point in the program. If a join point matches the pointcut, an advice handler is installed. The pointcut is represented as an abstract syntax tree (AST). The AST's match_define method is called for each join point.

The advice handlers become part of the normal program flow. Advice handlers execute the advice code under different circumstances for different types of pointcut operators. Each pointcut operator has, alongside the DT test (match_define), also a RT test (match_run).

For a calls() pointcut operator, the test always evaluates to true: Since it only matches call join points at DT then once it's installed, the code runs. There is no further condition.

For a cflow() pointcut operator, a DT match doesn't mean that the advice code will run all the time; it will only run if the RT control flow matches the cflow() argument.

Example:

  advice( calls('get') && cflow(qr/^Graphics/), sub { ... } )

means the following: at DT, calls() matches call join points where the sub name is 'get', and cflow() matches any join point, i.e. its match_define is always true. At RT, the pointcut expression is evaluated again, using the same AST as was constructed at DT, but this time with run time tests (i.e., using match_run): calls() always matches since it's installed, but cflow() matches only if caller() at some point matches /^Graphics/; and because of '&&', both RT tests must be true. If the pointcut expression matches, the advice code runs.

Like httpd is a web server, AOP can be seen as a server, where there are several phases during which aspects can change things in the program's flow.

Aspect order: if several aspects' pointcut affect a given join point, then the advice code of the aspect that has been defined later is run first.

Implement design patterns (cf. GoF). Make patterns first-class citizens.

Separation of concerns: separate the basic algorithms from special-purpose concerns such as synchronization, real-time constraints, and location control.

Use Aspects where they make sense; don't use them where they don't make sense. Like with OOP and Perl.

Combine aspects with other Perl technology: quantum aspects, aspects and coroutines, aspects and attributes, aspects and threads, aspects during compilation (B::*; compile-time join points; insert potential advice handlers during opportune moments, e.g. at the beginning and end of loops, after variable assignments etc.)

"Dynamic extension of class structure for duration of a task. This removes the pollution of the class graph with information which is only needed for a specific task." -- http://www.ccs.neu.edu/research/demeter/biblio/context.html

Possible Publicity

Perl monger mailing lists
use.perl journal
articles

In online and offline magazines (perl.com, tpj, consumer mags).

Search engines and directories
aspect.perl.org -> aspect.unixbeard.net ?
lists.perl.org

entry for the perl-aspects mailing list.

conference talks
AOP conferences

Check AOSD 2002: http://trese.cs.utwente.nl/aosd2002.htm.

AUTHOR

Marcel Grünauer <marcel@cpan.org>

COPYRIGHT

Copyright 2001-2002 Marcel Grünauer. All rights reserved.

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

SEE ALSO

Aspect::Intro(3pm), Aspect(3pm).