NAME
Sub::Block - manipulate blocks of code to assemble them into subs
SYNOPSIS
use Sub::Block;
my $plus_one = block { $_[0] + 1 };
print $plus_one->(7); # 8
STATUS
This is all pretty experimental at the moment. Consider it to be a
proof-of-concept.
DESCRIPTION
Sub::Block allows you to create objects that are conceptually code
blocks that can be composed with other code blocks to create subs which,
when called, will run the code in the blocks without all of the overhead
associated with a normal sub call.
Another way to think about it is that it's a cleaner way of building
closures than stringy eval.
Assume for example that you have a coderef $is_even which checks whether
a sub number is even, and you want to use "grep" to find all the even
numbers in a list:
my $is_even = sub { $_[0] % 2 == 0 };
my @even_nums = grep { $is_even->($_) } @list;
If @list is 10,000 items long, the $is_even sub is called 10,000 times.
Sub calls are relatively expensive in terms of CPU time, so it would be
good if we could inline the contents of $is_even into the "grep" block,
and thus avoid those 10,000 sub calls. With Sub::Block this is possible!
my $is_even = block { $_[0] % 2 == 0 };
my $grep_even = eval sprintf(
'sub { grep { %s } @_ }',
$is_even->inlininfy('$_'),
);
# Below this comment, only a single sub call happens!
my @even_nums = $grep_even->(@list);
Constructors
"new($coderef)"
Creates a Sub::Block from an existing coderef.
"new($string, \%captures)"
Creates a Sub::Block from a string of Perl code, plus a hashref of
variables to capture.
"block { BLOCK }"
This is not a method, but an exported function that acts as a
shortcut for the constructor.
Methods
"sub"
Returns the code block as a normal coderef.
"&{}" is overloaded so that "$block->(@args)" works.
"execute(@args)"
Executes the code block, with @args.
"closures"
Returns the variables closed over by the code block.
Note that Sub::Block is powered by Sub::Quote, and closures don't
really work properly. See
<https://rt.cpan.org/Ticket/Display.html?id=87315>.
"code"
Returns a string of Perl code for the code block.
"inlinify(@varnames)"
Returns a string of Perl code for the code block, wrapped in a
"do{...}" block with @_ localized and the variables in @varnames
assigned to it. The following:
my $plus_one = block { $_[0] + 1 };
print $plus_one->inlinify('$foo');
Will print something like:
do {
local @_ = ($foo);
$_[0] + 1
};
"grep"
A shortcut for the example earlier in this documentation:
my $is_even = block { $_[0] % 2 == 0 };
my $grep_even = $is_even->grep;
my @even_nums = $grep_even->execute(@list);
But $grep_even is a Sub::Block, not a normal coderef
"map"
Like "grep", but "map". :-)
"sequence(@others)"
Given a list of other blocks (or coderefs, which will be converted
into code blocks) generates a new block which calls all of the
blocks in sequence, with the output of each being passed into the
input of the next.
my $block1 = block { ... };
my $block2 = block { ... };
my $block3 = block { ... };
# The following two are conceptually similar.
my $seq1 = $block1->sequence($block2, $block3);
my $seq2 = block {
$block3->execute(
$block2->execute(
$block1->execute(@_)
)
);
};
You can also use the overloaded ">>" operator:
my $seq3 = $block1 >> $block2 >> $block3;
Or it can be called as a class method:
my $seq4 = Sub::Block->pipe($block1, $block2, $block3);
CAVEATS
Sub::Block is affected by
<https://rt.cpan.org/Ticket/Display.html?id=87315>.
The "return", "wantarray" and "caller" functions which rely on the sub
call stack will not see your code block when it's been inlined into an
outer sub. So "return" will really return from the outer sub, not the
code block.
Sub::Block will issue a warning if it notices that you've used one of
these keywords in your code block, but it might not always notice. (It
needs to walk the optree to look for them.)
BUGS
Please report any bugs to
<http://rt.cpan.org/Dist/Display.html?Queue=Sub-Block>.
SEE ALSO
Sub::Quote.
AUTHOR
Toby Inkster <tobyink@cpan.org>.
COPYRIGHT AND LICENCE
This software is copyright (c) 2013 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.