NAME

Sub::Filter - automatically filter function's return value

SYNOPSIS

use Sub::Filter qw(mutate_sub_filter_return);

mutate_sub_filter_return(\&get_height, \&num_checker);

use Sub::Filter qw(filter_return);

sub get_height :filter_return(num_checker) { ...

DESCRIPTION

This module allows a function to be augmented with a filter that will be applied to its return values. Whenever the function returns, by whatever means, the value (or list of values) being returned is passed through the filter before going to the caller. The filter may be any function, and may perform type checking/coercion, logging, or any other manipulation. The filtering is invisible to the body of the augmented function: the stack shows its normal caller, not a wrapping stack frame.

Return filtering

When using a return filter, the resulting augmented function is effectively composed from two simpler functions, the main function and the filter function. When the augmented function is called, first the main function executes, then when that returns the filter function has a chance to munge the return value. The main function doesn't actually have an independent callable identity. The filter function, however, is completely distinct, callable in its own right, and can act as a filter for several augmented functions simultaneously.

When the main function executes, it appears to be being called independently in the normal manner. The caller function shows that the immediate caller is whatever code actually called the augmented function, and lower-level tricks that get a more detailed view of the stack show the same situation. The main function body is aware of the calling context as usual, which it can check using wantarray.

When the main body returns, the filter function is implicitly called. caller will show that it is called from (the return statement of) the augmented function. The filter function executes with the same calling context that the main function had, and whatever the filter function returns will be used as the return value of the augmented function. The values returned by the main function body are available to the filter function as its arguments. The nature of these arguments will depend on the calling context: in scalar context it will be exactly one value, and in void context it will be no values at all. The filter function must be prepared for these situations.

If the main function, written in Perl, does a goto &, this replaces the entire stack frame of the augmented function, and the filter function will not be called. Likewise, "unwind" in Scope::Upper can bypass the filter, returning directly to the caller of the augmented function. These are ugly tricks that mess with the stack. Throwing an exception, by die, also causes the filter not to run, but in this case there is no return value to filter.

The main function to which a filter is to be applied may be either pure Perl or XS (native code, usually written in C). The filter function may also be either pure Perl or XS, and either type of filter function can be attached to either type of main function. It is also possible to apply multiple filters to one main function, effectively using an augmented function (main plus filter) as the main function to attach another filter to.

FUNCTION

mutate_sub_filter_return(SUB, FILTER)

SUB and FILTER must both be references to subroutines. SUB is modified in place, such that whatever SUB returns will be filtered through FILTER. The subroutine's identity is not changed, but the behaviour of the existing subroutine is changed. Beware of action at a distance.

This is best done at compile time, preferably in a BEGIN block immediately after the initial definition of SUB. It is preferable, where possible, to use the subroutine attribute described below. This function exists mainly for awkward situations where the attribute is difficult to use.

SUBROUTINE ATTRIBUTE

The visibility of this attribute is controlled by lexical (block) scoping, managed by Attribute::Lexical. To make it available in the current block, include filter_return in the import list in the use statement for this module, as shown in the synopsis.

:filter_return(FILTER)

The function to which this attribute is applied will be augmented, such that whatever it returns will be filtered through the function specified by FILTER.

FILTER must be the name of a function. It may be either fully-qualified (e.g., Foo::num_checker), or an unqualified name (e.g., num_checker) referring to a function in the current package (current where the attribute is used). (It is not possible to use an anonymous filter function this way; see "mutate_sub_filter_return" if you need to do that.)

BUGS

A filter cannot be attached to a Perl function that shares its op tree with another. This can happen due to threading, or due to closures (where all closures from a single source share one op tree). This limitation should be removed in a future version. The problem does not occur if a filter is attached before the sharing arises.

Filtering on an lvalue subroutine currently breaks the lvalue behaviour.

The way a filter is attached to a pure Perl main function confuses B::Deparse. The resulting augmented function consists of a network of op nodes, just like a pure Perl function, but the nodes fit together in a structure that the Perl compiler never generates. This is ultimately because the call to the filter function is difficult to express in pure Perl, due to the context-dependent behaviour.

SEE ALSO

Attribute::Lexical, Sub::Mutate

AUTHOR

Andrew Main (Zefram) <zefram@fysh.org>

COPYRIGHT

Copyright (C) 2009, 2010, 2013 Andrew Main (Zefram) <zefram@fysh.org>

LICENSE

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