NAME
returning - define subs that act like "return"
SYNOPSIS
use Test::Simple tests => 1;
use returning {
Yes => 1,
No => 0,
};
sub beats_sissors
{
local $_ = shift;
No if /paper/i;
Yes if /rock/i;
No if /scissors/;
}
ok beats_scissors("rock");
DESCRIPTION
The "returning" module allows you to define subs which act like
"return". That is, they break out of their caller sub. In the SYNPOSIS
example, the "/scissors/i" regexp is never even evaluated because the
"Yes" statement breaks out of the the sub, returning "1". The
"beats_scissors" function could have alternatively been written as:
sub beats_sissors
{
local $_ = shift;
return 0 if /paper/i;
return 1 if /rock/i;
return 0 if /scissors/;
}
"returning" may be especially useful for domain-specific languages.
Usage
There are three ways to define a returning sub using this module:
use returning { subname => 'value' };
This creates the sub in the caller's namespace called " subname " with
an empty prototype. (So when calling the sub, you don't need to use
parentheses; just like with constant subs, but without as much
optimization.)
use returning { subname => sub { ... } }
This installs the provided sub into the caller's namespace. This allows
you to define non-constant subs, including subs that take parameters and
do interesting stuff with them.
BEGIN {
sub subname { ... }
};
use returning 'subname'; # look, no hashref!
This does not install any sub into the caller's namespace, but modifies
an existing sub to act in a returning way. Note that because "use"
operates at compile time, you need to take a lot of care to ensure that
the sub has already been defined.
These can be combined, a la...
use constant ZeroButTrue => '0E0';
use returning 'ZeroButTrue', {
Affirm => !!1,
Deny => !!0,
Mu => sub { return; },
}
Implementation Notes
My first stab at this used Devel::Declare, but I couldn't quite get it
working, and nobody in "#devel-declare" seemed sure why it was not. It
seems possible that the ability to do this lies slightly beyond what
Devel::Declare is capable of.
Instead Scope::Upper has been used to create wrappers which jump up one
more subroutine than expected when they return. This means that some of
the magic happens at run-time rather than compile-time, so it perhaps
executes slightly slower, but probably compiled slightly faster.
An advantage of Scope::Upper is that you can re-export your "returning"
subs to other packages with no problem, and they'll continue to have
their special behaviour with no extra effort.
A feature I had been hoping to achieve with Devel::Declare would be for
calling a sub with an ampersand ("&Affirm()") to act as a way of
avoiding the magic behaviour. This has not been possible with
Scope::Upper.
Class Method
"returning->setup_for($package, $subname)"
Given the package name and subname of an *existing* sub, sets up the
magic.
BUGS
Please report any bugs to
<http://rt.cpan.org/Dist/Display.html?Queue=returning>.
SEE ALSO
"Scope::Upper" takes care of most of the black magic.
AUTHOR
Toby Inkster <tobyink@cpan.org>.
CREDITS
Thanks OSFAMERON, Matt S Trout (MSTROUT), and Ash Berlin (ASH), for
helping me through some of the tricky bits.
COPYRIGHT AND LICENCE
This software is copyright (c) 2012 by Toby Inkster.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.