Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
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
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.
        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.
        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

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 making s'mores by the fire in the courtyard of the Monastery: (8)
As of 2014-12-18 00:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (41 votes), past polls