Aspect::Pointcut - API for determining which events should be hooked
Aspect-Oriented Programming implementations draw much of their power from the
flexibility that can be applied to when a function call should or should not
provides a robust and powerful API for defining the rules
for when a function call should be hooked, and then applying the rules as
optimally as possible. This optimisation is particularly important for any
pure-Perl implementation, which cannot hook deeply into the underlying virtual
machine as you might with a Java or Perl XS-based implementation.
A running program can be seen as a collection of events. Events like a sub
returning from a call, or a package being used. These are called join points.
A pointcut defines a set of join points, taken from all the join points in the
program. Different pointcut classes allow you to define the set in different
ways, so you can target the exact join points you need.
Pointcuts are constructed as trees; logical operations on pointcuts with one or
two arguments (not, and, or) are themselves pointcut operators. You can
construct them explicitly using object syntax, or you can use the convenience
functions exported by Aspect and the overloaded operators "!",
"&" and "|".
The "new" constructor creates new pointcut objects.
All pointcut classes define their own rules around the parameters that are
provided, but once created these pointcuts can then all be mixed together in
an arbitrary fashion.
Note: Unlike most Perl objects the default and recommended underlying datatype
for pointcut objects is an "ARRAY" reference rather than
"HASH" references. This is done because pointcut code can directly
impact the speed of function calls, and so is extremely performance sensitive.
my @fully_resolved_function_names = $pointcut->match_all;
The "match_all" method is the primary compile-time function called on
the pointcut model by the core Aspect library.
It will examine the list of all loaded functions and identify those which could
potentially match, and will need to have hooks installed to intercept calls to
These functions will not necesarily all result in Aspect code being run. Some
functions may be called in all cases, but often further run-time analyis needs
to be done before we can be sure the particular function call respresents a
Returns a list of fully-resolved function names (e.g.
my $should_hook = $pointcut->match_define;
At compile time, the only common factor in predicting the future state of a
function call is the name of the function itself.
The "match_define" method is called on the pointcut for each
theoretically-matchable function in the entire Perl namespace that part of an
ignored namespace, passing a single parameter of the fully-resolved function
The method will determine if the function might
match, and needs to be
hooked for further checking at run-time, potentially calling
"match_define" on child objects as well.
Returns true if the function might match the pointcut, or false if the function
can never possibly match the pointcut and should never be checked at run-time.
The "compile_weave" method generates a custom function that is used to
test if a particular named function should be hooked as a potential join
The "compile_runtime" method generates a custom function that is used
to test if a particular named function should be hooked as a potential join
my $calls = $pointcut->match_contains('Aspect::Pointcut::Call');
The "match_contains" method provides a convenience for the validation
and optimisation systems. It is used to check for the existance of a
particular condition type anywhere within the pointcut object tree.
Returns the number of instances of a particular pointcut type within the tree.
my $always = $pointcut->match_contains('Aspect::Pointcut::Throwing');
The "match_always" method provides a convenience for the validation
and optimisation systems. It is used to check that a particular condition type
will be tested at least once for a matching join point, regardless of which
path the match takes through branching pointcut logic.
Returns true if an expression type is encounter at least once in all branches,
or false if there is any branch path that can be taken in which the condition
won't be encountered.
my $optimized_pointcut = $raw_pointcut->curry_runtime;
In a production system, pointcut declarations can result in large and complex
Because this tree can contain a large amount of structure that is no longer
relevant at run-time, it can end up making a long series of prohibitively
expensive cascading method or function calls before every single regular
To reduce this cost down to something more reasonable, pointcuts are run through
a currying process (see <http://en.wikipedia.org/wiki/Currying>).
A variety of optimisations are used to simplify boolean nesting, to remove tests
that are irrelevant once the compile-time hooks have all been set up, and to
remove other tests that the currying process can determine will never need to
The currying process will generate and return a new pointcut tree that is
independent from the original, and that can perform a match test at the
structurally minimum computational cost.
Returns a new optimised Aspect::Pointcut
object if any further testing
needs to be done at run-time for the pointcut. Returns null ("undef"
in scalar context or "()" in list context) if the pointcut can be
curried away to nothing, and no further testing needs to be done at run-time.
The "curry_weave" method is similar to the "curry_runtime"
method, except that instead of reducing the pointcut to only elements that are
relevant at run-time, it reduces the pointcut to only elements that are
relevant at weave time.
By remove purely run-time elements, the compile weave test code is made both
faster and more accurate (some complicated situations can occur when there is
a Aspect::Pointcut::Not in the tree).
Adam Kennedy <email@example.com>
Marcel Gruenauer <firstname.lastname@example.org>
Ran Eilam <email@example.com>
Copyright 2001 by Marcel Gruenauer
Some parts copyright 2009 - 2013 Adam Kennedy.
This library is free software; you can redistribute it and/or modify it under
the same terms as Perl itself.