Aspect::Pointcut(3pm)

πŸ“¦
version 1.04 Β· 3 versions
, in debian trixie, ubuntu noble, ubuntu resolute, ubuntu stonking

πŸŽ€ NAME πŸŽ€

Aspect::Pointcut β€” the API that decides which events get hooked, bestie. This is the page from the User Contributed Perl Documentation section of the manual, and it's genuinely one of the more iconic ones. πŸ’…


✨ DESCRIPTION ✨

Okay so, Aspect-Oriented Programming implementations get so much of their power from the flexibility around when a function call should or shouldn't be hooked. That's the whole game.

Aspect::Pointcut gives you a robust and powerful API for defining the rules about when a function call should get hooked, and then applying those rules as optimally as humanly possible. And this optimisation thing? Not optional, bestie. It's especially important for any pure-Perl implementation, because a pure-Perl one can't hook deeply into the underlying virtual machine the way you could with a Java or Perl XS-based implementation. So we gotta be clever instead. 🧠✨

Think of a running program as a whole 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, picked out of all the join points in the program. Different pointcut classes let you define that set in different ways, so you can target the exact join points you need. It's giving precision. It's giving control. 🎯

Pointcuts are constructed as trees β€” logical operations on pointcuts with one or two arguments (not, and, or) are themselves pointcut operators. You can build them explicitly using object syntax, or you can use the convenience functions exported by Aspect plus the overloaded operators !, & and |. Pick your vibe. πŸ¦‹


🌸 METHODS 🌸

πŸ’– new

The new constructor creates new pointcut objects. Fresh out the box, no cap.

All pointcut classes define their own rules around the parameters that are provided, but once they're created, these pointcuts can all be mixed together in an arbitrary fashion. Free-for-all. Love that for them.

Note: Unlike most Perl objects, the default and recommended underlying datatype for pointcut objects is an ARRAY reference rather than HASH references. Why? Because pointcut code can directly impact the speed of function calls, and so it is extremely performance sensitive. Respect the ARRAY, she's doing important work. 🫢

πŸ’– match_all

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. Main character behaviour, honestly.

It goes through the list of all loaded functions and identifies the ones which could potentially match, and which will need hooks installed to intercept calls to those functions.

Now β€” 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 match. So like... potential, not promise. πŸ’€

Returns a list of fully-resolved function names (e.g. Module::Name::function).

πŸ’– match_define

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. That's literally all we've got to work with. 😭

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

The method will figure out 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. It's recursive, bestie. It goes deep. 🌈

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.

πŸ’– compile_weave

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

πŸ’– compile_runtime

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

πŸ’– match_contains

my $calls = $pointcut->match_contains('Aspect::Pointcut::Call');

The match_contains method is a convenience for the validation and optimisation systems. It checks for the existance of a particular condition type anywhere within the pointcut object tree. Anywhere. Like a little detective. πŸ”

Returns the number of instances of a particular pointcut type within the tree.

πŸ’– match_always

my $always = $pointcut->match_contains('Aspect::Pointcut::Throwing');

The match_always method is also a convenience for the validation and optimisation systems. It checks 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. So basically: "does every road lead here, or is there an escape hatch?" πŸ›£οΈ

πŸ’– curry_runtime

my $optimized_pointcut = $raw_pointcut->curry_runtime;

In a production system, pointcut declarations can result in large and complex Aspect::Pointcut object trees. And bestie, when I say large, I mean large.

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 function call. Not the vibe. Absolutely not the vibe. πŸ’€

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 be tested. Spring cleaning, but make it computational. 🧹✨

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. Poof. Gone. Curried into the void. πŸ«₯

πŸ’– curry_weave

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 β€” because some complicated situations can occur when there is a Aspect::Pointcut::Not in the tree. Not the Not causing chaos. πŸ™ˆ


πŸ‘‘ AUTHORS πŸ‘‘

  • Adam Kennedy <adamk@cpan.org>
  • Marcel GrΓΌnauer <marcel@cpan.org>
  • Ran Eilam <eilara@cpan.org>

Copyright 2001 by Marcel GrΓΌnauer

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.


okay that's the whole page bestie, you ate it, no crumbs πŸ“ and for the record this all came from the User Contributed Perl Documentation, Aspect::Pointcut(3pm), from perl v5.36.0, dated 2023-07-02. slay, go hook something. πŸ’…βœ¨

πŸ“¦ where this page comes from