Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Does there exist a CPAN module for lazily initialized variables?

by jryan (Vicar)
on Jul 14, 2004 at 18:35 UTC ( #374384=perlquestion: print w/ replies, xml ) Need Help??
jryan has asked for the wisdom of the Perl Monks concerning the following question:

Just a small question: does a module to laziliy initialize a tied variable exist on the CPAN? Basically, I have a bunch class variables that are each initialized separately by a relatively expensive operation (database access, reading in an xml file, etc). Since I'm not programming Java, I would feel silly creating a separate Singleton class for each one of these things. All I really want to do is use them like normal variables, and just have them become magically initialized during their first use. As a quick first rev, I hacked this up:

package Tie::LazyInitialized::Hash; use strict; require Tie::Hash; our @ISA = 'Tie::StdHash'; my $sub; sub TIEHASH { my ($class, $callback, @args) = @_; $sub = sub { $callback->(@args) }; bless {}, $class; } sub FETCH { my ($self, $key) = @_; %$self = %{ $sub->() } unless %$self; # hehe, i wonder if %&$sub w +ould work? $self->{$key} } 1;

But, as soon as I finished typing the last ;, I figured that there *must* be a general CPAN module to do this. However, given that not being able to find things on CPAN is something of a knack of mine, I haven't found anything like what I need. I'd much-much-much rather use a CPAN module than this little hacked up thing. Does anyone know if one exists?

Comment on Does there exist a CPAN module for lazily initialized variables?
Download Code
Replies are listed 'Best First'.
Re: Does there exist a CPAN module for lazily initialized variables?
by dragonchild (Archbishop) on Jul 14, 2004 at 18:40 UTC
    Ideally, the module used would be a dispatcher to the actual module needed, similar to how File::Spec dispatches to the right File::Spec::* module, depending on OS. So, you'd actually have Tie::Lazy and Tie::Hash::Lazy / Tie::Scalar::Lazy / etc. I think that would meet brian_d_foy's need for well-named distros ...

    Is there a way of doing that kind of auto-detection?

    ------
    We are the carpenters and bricklayers of the Information Age.

    Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose

    I shouldn't have to say this, but any code, unless otherwise stated, is untested

      The only way I can think of is to put all three sets of tie-methods in the same package, and let dispatch to the right ones automagically (with a bit of extra logic to deal with the common methods). I did this in Sub::Sealed, but that was a joke module, so I didn't really bother to find out if that was best-practice.

Re: Does there exist a CPAN module for lazily initialized variables?
by lachoy (Parson) on Jul 14, 2004 at 18:52 UTC
    Object::Realize::Later does not explicitly deal with tied variables but seems to be flexible enough to do what you want.

    Chris
    M-x auto-bs-mode

      It almost seems... *too* flexible. :) My whole jive is that I don't want to go through the trouble of creating these Singleton classes, which it seems like I'd have to do with Object::Realize::Later anyways. Thanks for the tip, though; with my extremely inept searching abilities, I don't think I would have found Object::Realize::Later on my own.

      Update: Another thought: I might be able to use Object::Realize::Later to create only a small single class that handles the automatic initialization... although that also might be more trouble than its worth...

Re: Does there exist a CPAN module for lazily initialized variables?
by sgifford (Prior) on Jul 14, 2004 at 19:04 UTC
    How about using a sub that initializes the variable if it's unset, then returns the variable? I do this with DBI quite often. Something like:
    { my $dbh; sub dbh { if (!$dbh) { # initialize dbh } $dbh; }

    Then you can say things like:

    dbh()->prepare("..."); dbh()->do("...");

    Think of the subs as very complex variable declarations. :)

      Right, that's the thing; I have code that's essentially just like that all over the damn place. I'm trying to refactor/clean it up right now.
        sub build_lazy { my ($var, $callback, @params) = @_; eval <<__EVAL__; { my \$$var; sub $var { \\\$var = $callback->(@params) unless defined \$$var; \$$var; }; } __EVAL__ } # Later ... build_lazy( 'dbh', \&build_dbh, @dbh_params ); build_lazy( 'foo', \&build_foo );

        Of course, you might want some dwimmery for hashes vs. arrays vs. scalars, unless you're ok with everything as a reference. I would be, but that's just me. And, you might want to throw BEGIN or CHECK around the calls to build_lazy(), but that's probably overkill.

        ------
        We are the carpenters and bricklayers of the Information Age.

        Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose

        I shouldn't have to say this, but any code, unless otherwise stated, is untested

        I really like dbh() because it gives you a runtime chance to automatically reconnect or refresh or whatever as needed which you wouldn't get if you just accessed a global $DBH.
Re: Does there exist a CPAN module for lazily initialized variables?
by Arunbear (Parson) on Jul 15, 2004 at 10:13 UTC
      Yeah, actually, thanks. At least as far as the scalar goes. The hash and array are done by element, making them kinda useless for me. I guess I can just change everything to use references...
Tie::Memoize and Memoize.pm (Was "Re: Does there exist a CPAN module for lazily initialized variables?")
by ihb (Deacon) on Jul 15, 2004 at 16:28 UTC

    Even better, there's a standard module for this: Memoize.pm, if the function approach is good enough.

    Example:

    use Memoize; BEGIN { *dbh = memoize(sub () { DBI::->connect(...) }) } dbh()->foo; # connect and do foo. dbh()->bar; # use cached object and do bar.
    The BEGIN block isn't necessary, but it'll make the prototype work.

    I can't test it, but I don't see why it shouldn't work.

    Update: If you really want a variable you may want to check out Tie::Memoize which also is a standard module I think. It uses hashes.

    ihb

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (14)
As of 2015-07-29 22:40 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 (269 votes), past polls