Data::Lazy.pm - "lazy" variables |
Data::Lazy.pm - ``lazy'' (defered/on-demand) variables
version 0.6
(obsoletes and replaces Lazy.pm)
# short form use Data::Lazy variablename => 'code'; use Data::Lazy variablename => \&fun; use Data::Lazy '@variablename' => \&fun;
# to use options, you need to `use' the module first. use Data::Lazy; tie $variable, 'Data::Lazy', sub { ... }, LAZY_READONLY;
# magic untie - slow on (broken) Perl 5.8.0 tie $variable, 'Data::Lazy' => \$variable, sub { ... };
A very little module for generic on-demand computation of values in a scalar, array or hash.
It provides scalars that are ``lazy'', that is their value is computed only when accessed, and at most once.
tie $variable_often_unnecessary, 'Data::Lazy', sub {a function taking a long time} [, $store_options];
tie $var, 'Data::Lazy', 'a string containing some code' [, $store_options];
use Data::Lazy variablename => 'code' [, $store_options];
use Data::Lazy '$variablename' => \&function [, $store_options];
The first time you access the variable, the code gets executed and the result is saved for later as well as returned to you. Next accesses will use this value without executing anything.
You may specify what will happen if you try to reset the variable. You may either change the value or the code.
tie $var, 'Data::Lazy', 'sleep 1; 1'; # or tie $var, 'Data::Lazy', 'sleep 1; 1', LAZY_STOREVALUE; $var = 'sleep 2; 2'; print "'$var'\n";
will return:
'sleep 2; 2'
tie $var, 'Data::Lazy', 'sleep 1; 1', LAZY_STORECODE; $var = 'sub { "4" }'
will return
'4'
with no delay.
If you tie the variable with LAZY_STORECODE option and then undefine
the variable (via undef($variable)
), only the stored value is
forgotten, and next time you access this variable, the code is
re-evaluated.
croak()
(see the Carp manpage). That is,
tie $var, 'Data::Lazy', 'sleep 1; 1', LAZY_READONLY; $var = 'sleep 2; 2'; print "'$var'\n";
Will give you an error message :
Modification of a read-only value attempted at ...
tie $var, 'Data::Lazy', \$var, "sleep 1; 1";
Note that LAZY_UNTIE was not specified; the reference to the variable was automatically spotted in the input list.
It's possible to create several variables in one ``use Data::Lazy ...'' statement.
The default tie mode for arrays makes individual items subject to similar behaviour as scalars.
eg.
tie @variable, 'Data::Lazy', sub { my $index = shift; ... };
tie @var, 'Data::Lazy', 'my $index = shift; ...';
use Data::Lazy '@variablename' => \&function;
The first time you access some item of the list, the code gets executed with $_[0] being the index and the result is saved for later as well as returned to you. Next accesses will use this value without executing anything.
You may change the values in the array, but there is no way
(currently) to change the code, other than (tied @foo)->{'code'}
= sub {...}
(which is considered cheating).
eg.
tie @var, 'Data::Lazy', sub {$_[0]*1.5+15}; print ">$var[1]<\n"; $var[2]=1; print ">$var[2]<\n";
tie @fib, 'Data::Lazy', sub { if ($_[0] < 0) {0} elsif ($_[0] == 0) {1} elsif ($_[0] == 1) {1} else {$fib[$_[0]-1]+$fib[$_[0]-2]} }; print $fib[15];
Currently it's next to imposible to change the code to be evaluated in
a Data::Lazy array. Any options you pass to tie()
are ignored.
Patches welcome.
The size of an array, as returned by evaluating it in scalar context
or the $#var
syntax, will return the highest index returned already
- or 0 if nothing has been read from it yet. Note that this behaviour
has changed from version 0.5, where 1 was returned on a fresh tied
array.
Eg.
tie %variable, Data::Lazy, sub {a function taking a long time};
tie %var, Data::Lazy, 'a string containing some code';
use Data::Lazy '%variablename' => \&function;
The first time you access some item of the hash, the code gets executed with $_[0] being the key and the result is saved for later as well as returned to you. Next accesses will use this value without executing anything.
If you want to get or set the code that's being evaluated for the previously unknown items you will find it in $variable{$;}. If you change the code all previously computed values are discarded.
Ex. tie %var, Data::Lazy, sub {reverse $_[0]}; print ">$var{'Hello world'}<\n"; $var{Jenda}='Jan Krynicky'; print ">$var{'Jenda'}<\n"; $fun = $var{$;}; $var{$;} = sub {$_ = $_[0];tr/a-z/A-Z/g;$_}; print ">$var[2]<\n";
If you write something like
while (($key,$value) = each %lazy_hash) { print " $key = $value\n"; # };
only the previously fetched items are returned. Otherwise the listing could be infinite :-)
If you want to access the code or value stored in the variable directly you may use
${tied $var}{code} and ${tied $var}{value} # scalar $var ${tied @var}{value}[$i] # array @var ${tied %var}{value}{$name} # hash %var
This way you may modify the code even for arrays and hashes, but be very careful with this. Of course if you redefine the code, you'll want to undef the {value}!
There are two more internal variables:
${tied $var}{type} 0 => scalar 1 => array 2 => hash ${tied $var}{store} 0 => LAZY_STOREVALUE 1 => LAZY_STORECODE 2 => LAZY_READONLY
If you touch these, prepare for very strange results!
An object-oriented interface to setting these variables would be easily added (patches welcome).
1. use Data::Lazy; tie $x, 'Data::Lazy', sub{sleep 3; 3}; # or # use Data::Lazy '$x' => sub{sleep 3; 3};
print "1. "; print "$x\n"; print "2. "; print "$x\n";
$x = 'sleep 10; 10';
print "3. "; print "$x\n"; print "4. "; print "$x\n";
2. (from Win32::FileOp) tie $Win32::FileOp::SHAddToRecentDocs, 'Data::Lazy', sub { new Win32::API("shell32", "SHAddToRecentDocs", ['I','P'], 'I') or die "new Win32::API::SHAddToRecentDocs: $!\n" }; ...
Please note that there are single guotes around the variable names in ``use Data::Lazy '...' => ...'' statements. The guotes are REQUIRED as soon as you use any variable type characters ($, @ or %)!
There are several notable alternatives to this module; if you come across another, please forward mention to the author for inclusion in this list.
Due to incomplete support for tie'ing arrays in very old versions of Perl (ie, before 5.004), to fetch the size of an array, you cannot just evaluate it in scalar context; you have to use:
tied(@a)->{'size'}
the usual;
scalar(@a); # or ($#a + 1)
will return zero! :-(
Jan Krynicky <Jenda@Krynicky.cz>
Copyright (c) 2001 Jan Krynicky <Jenda@Krynicky.cz>. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Some changes copyright (c) 2004, Sam Vilain <samv@cpan.org>. All rights reserved. Changes distributed under terms of original license.
Data::Lazy.pm - "lazy" variables |