Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

A Lazy Class

by Zaxo (Archbishop)
on Apr 21, 2002 at 14:46 UTC ( [id://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

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
Domain Nodelet?
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?Last hourOther CB clients
Other Users?
Others examining the Monastery: (7)
As of 2024-04-23 11:27 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found