Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

A Lazy Class

by Zaxo (Archbishop)
on Apr 21, 2002 at 14:46 UTC ( #160883=perlquestion: print w/ replies, xml ) Need Help??
Zaxo has asked for the wisdom of the Perl Monks concerning the following question:

I have use for a boolean class which is lazy evaluated. That is, it will take no value until needed, after which its value is memoized.

I want this for testing complicated nests of logical operators, but a similar construction would be useful for expensive functions.

I've implemented this in terms of a closure in the constructor and overload 'bool'. I'm not very satisfied with the implementation. The $foo->{peek}{} notation for the closures is really ugly, but I like the way overloading works here. I'd appreciate any suggestions for a cleaner interface. Is there an idiom for this? Would tie help?

Here's the module and a demo script:

#!/usr/bin/perl -w use strict; package LazyBool; use constant THE_BIT => 1 << 9; use constant RAND_SIZE => 1 << 16; use overload 'bool' => sub { my $self = shift; $self->{value}(); }; sub new { my $class = shift; my ($value,$self) = (undef,{}); $self->{value} = sub { defined $value ? $value : $value = THE_BIT & rand(RAND_SIZE) ? 1 : 0; }; $self->{peek} = sub { $value; }; bless $self, $class; } 1;
lazybool.pl:
#!/usr/bin/perl -w use strict; use LazyBool; my $foo = LazyBool->new; print '$foo is ', defined $foo->{peek}() ? $foo->{peek}() : "not defined", '.', $/; print $foo,$/; print '$foo is ', defined $foo->{peek}()? $foo->{peek}() : "not defined", '.', $/; =pod $ perl lazybool.pl $foo is not defined. 0 $foo is 0. $ perl lazybool.pl $foo is not defined. 0 $foo is 0. $ perl lazybool.pl $foo is not defined. 1 $foo is 1. =cut

After Compline,
Zaxo

Comment on A Lazy Class
Select or Download Code
Replies are listed 'Best First'.
Re: A Lazy Class
by japhy (Canon) on Apr 21, 2002 at 15:00 UTC
    I'd use tie() instead. This module will untie the variable and replace it with its value the first time the variable is fetched.
    package Tie::Scalar::Lazy; # usage: # use Tie::Scalar::Lazy; # lazy $value => \&expensive_function; require Exporter; @ISA = qw( Exporter ); @EXPORT = qw( lazy ); sub lazy { tie $_[0], __PACKAGE__, \$_[0], $_[1]; } sub TIESCALAR { my ($class, $sref, $cref) = @_; bless [ $sref, $cref ], $class; } sub FETCH { my $self = shift; my $value = $self->[1]->(); untie ${ $self->[0] }; ${ $self->[0] } = $value; } 1;

    _____________________________________________________
    Jeff[japhy]Pinyan: Perl, regex, and perl hacker, who'd like a (from-home) job
    s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

      That's a gutsy play, japhy. I wonder if anyone has ever tested untying a value inside a FETCH method on that selfsame value? If not, I'd run the test under a memory leak detector. It wouldn't be hard for Perl to leak memory due to an unexpected circular dependency.

          -- Chip Salzenberg, Free-Floating Agent of Chaos

        I've done it before, and I'll do it again!

        _____________________________________________________
        Jeff[japhy]Pinyan: Perl, regex, and perl hacker, who'd like a (from-home) job
        s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

Re: A Lazy Class
by broquaint (Abbot) on Apr 21, 2002 at 15:27 UTC
    You could overload the stringify operator to get the current value of the object.
    #!/usr/bin/perl -w use strict; package LazyBool; use constant THE_BIT => 1 << 9; use constant RAND_SIZE => 1 << 16; use overload 'bool' => sub { my $self = shift; $self->{value}(); }; use overload q[""] => sub { my $self = shift; return defined $self->{peek}() ? $self->{peek}() : "not defined"; }; sub new { my $class = shift; my ($value,$self) = (undef,{}); $self->{value} = sub { defined $value ? $value : $value = THE_BIT & rand(RAND_SIZE) ? 1 : 0; }; $self->{peek} = sub { $value; }; bless $self, $class; } 1; package main; use strict; my $foo = LazyBool->new; print "\$foo is $foo", $/; print '$foo is true', $/ if $foo; print "\$foo is $foo", $/;
    It does essentially the same as your example code but just hides away the calls to $foo->{peek}() in the stringify operator. It seems the logical way to do it as you'll only be 'looking' at the value of $foo in a string context (well that's what $peek seems to allude to). That's what overloaded operators are for right?
    HTH

    broquaint

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://160883]
Approved by broquaint
Front-paged by broquaint
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (8)
As of 2015-07-07 23:11 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (93 votes), past polls