Sub::Lazy - defer calculating subs until necessary
use strict; use Test::More; use Sub::Lazy; my $it_happens = 0; sub double :Lazy { $it_happens++; # side-effect my $n = shift; return $n * 2; } my $eight = double(4); # The 'double' function hasn't been executed yet. is($it_happens, 0); # The correct answer was calculated. is($eight, 8); # The 'double' function was executed when necessary. is($it_happens, 1); done_testing;
Sub::Lazy allows you to mark subs as candidates for lazy evaluation. Good candidates for lazy evaluation:
Have no side-effects. They don't alter global variables; they don't make use of any closed-over lexical variables; they don't do IO or make system calls.
Are only called in scalar context. This module always imposes a scalar context on subs. (Of course the sub can return an arrayref.)
The actual work is done by Data::Thunk. Data::Thunk is awesome but it does have its limitations. It's not completely transparent (if you try hard enough, you can tell the difference between a value that has not been calculated yet and one that has) and it will sometimes be over-eager to calculate a value. But it's probably the best solution for lazy scalars on CPAN, so I've reused it rather than writing a half-arsed replacement for it.
This module defines an atttribute (:Lazy) to allow you to wrap a sub with Data::Thunk, making the whole business a little easier.
:Lazy
If your function is known to always return an instance of a particular class, then you can specify that:
sub get_manager :Lazy(class=>Person) { ...; }
Sub::Lazy will then use Data::Thunk's lazy_object feature, which allows Data::Thunk to further postpone evaluation of the sub in some cases.
lazy_object
You can even patch in further details about the object you are returning:
sub get_manager :Lazy(class=>Person,job_title=>"Manager") { ...; }
Now get_manager(...)->job_title will return "Manager" without needing to evaluate get_manager.
get_manager(...)->job_title
"Manager"
get_manager
Setting the PERL_SUB_LAZY_DISABLE environment variable to true allows you to disable the effects of this module. Subs will be run eagerly. This environment variable needs to be set prior to loading Sub::Lazy. It is a global off switch.
PERL_SUB_LAZY_DISABLE
Sub::Lazy::ENABLED
Checks the status of the global off switch.
Please report any bugs to http://rt.cpan.org/Dist/Display.html?Queue=Sub-Lazy.
Data::Thunk.
Toby Inkster <tobyink@cpan.org>.
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.
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.
To install Sub::Lazy, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Sub::Lazy
CPAN shell
perl -MCPAN -e shell install Sub::Lazy
For more information on module installation, please visit the detailed CPAN module installation guide.