NAME
MT::Promise - Faux-lazy evaluation for Perl
SYNOPSIS
sub work_hard { # some costly operation } use MT::Promise qw(delay lazy force); # slickest $meaning_of_life = lazy { work_hard(); return 42 }; # kinda slick $meaning_of_life = delay(sub { work_hard(); return 42 }); # clunky ... $meaning_of_life = new MT::promise(sub { work_hard(); return 42; }); print force($meaning_of_life); # prints: # 42
DESCRIPTION
A promise is like a value, but the value itself hasn't been computed yet. At any time, you can "force" the promise to get its value; the first time it's forced, the computation of the value takes place and the value is stored. Thereafter, forcing it uses the stored value instead of re-computing it.
This is useful if some bit of code may be expecting a value in a certain place, but you don't know up front whether that value will really be needed. To use this optimization, the expectant code needs to expect a promise, of course, since it has to call force
to get the value. But you don't have to worry about whether the value will be needed or which bit of code will need it first--that will shake out at runtime.
USAGE
lazy
There are three forms for creating promises. The lazy
form is the slickest:
my $red = foo($arg); my $value = lazy { $green = green($red); $blue = blue($red, $green); }
delay
The delay
form can be useful if you want to delay the evaluation of a routine that already has a name:
my $value = delay \&costly_function;
but it should be pointed out that costly_function in this case must be a thunk--it must not expect any arguments. Typically, you end up using a closure or the lazy
form to encapsulate the arguments:
my $value1 = lazy { fibonacci(8675309) };
This is almost precisely like $value2 = fibonacci(865309) except that (a) you have to force $value1, and (b) the 8675309th fibonacci won't be calculated if it's never force
d.
new
Last and least, you can use new
to create a promise, though it's clunkier than the other methods:
my $value = new MT::Promise(sub { fibonacci(8675309) });
This would be useful if you were sub-classing promise for some reason.
force
Force the promise to get its value. The first time, the computation of the value happens and the value is stored for subsequent access.
NOTES
Note that if you use the name of a variable declared outside the lazy block, such as
my $red; my $value = lazy { foo($red) }
then $value will carry around a reference to $red for as long as $value lives. This is important to keep in mind as it's possible to create a circular reference without realizing it. You've got to try pretty hard, though.
AUTHOR & COPYRIGHT
Please see "AUTHOR & COPYRIGHT" in MT.