Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Re^2: Making a variable in a sub retain its value between calls

by tlm (Prior)
on Apr 18, 2005 at 21:50 UTC ( [id://449043] : note . print w/replies, xml ) Need Help??


in reply to Re: Making a variable in a sub retain its value between calls
in thread Making a variable in a sub retain its value between calls

Update: In the days and weeks after the debate that followed this comment of mine, through reading and CB conversations I have convinced myself that INIT blocks are not "up to spec", so I'm avoiding them. See in particular TimToady's node in this thread.


In the TIMTOWTDI vein, I'm partial to INIT blocks myself:

use strict; use warnings; test() for (1..3); { my $memory; INIT { $memory = 'a' } sub test { print "Value of static var is ", $memory++, "\n"; } } __END__ Value of static var is a Value of static var is b Value of static var is c
I like using an extra internal INIT block only because it clearly sets the initialization code off from the rest.

Of course, if one doesn't like INIT or BEGIN blocks, one can always explicitly check in test that $memory has been initialized and remedy the situation if necessary, but that's ugly, IMO.

the lowliest monk

Replies are listed 'Best First'.
Re^3: Making a variable in a sub retain its value between calls
by ihb (Deacon) on Apr 18, 2005 at 23:41 UTC

    I'm partial to INIT blocks myself

    Noooooooooooo! Please please please don't do that! It will break if you put the code using the INIT block in a module and that modules is directly or indirectly required (i.e., loaded after program compile-time). INITs are not executed right after the file in which it was found is done compiling. It's executed after the program file is done compiling. INIT is used when you need to do something delay execution of something to before program run-time.

    Personally I go with adding a BEGIN before the bare block, thus avoiding to retype the variable name.

    BEGIN { my $memory = 'a'; sub test { print "Value of static var is ", $memory++, "\n"; } }

    Update: added clarification.

    ihb

    See perltoc if you don't know which perldoc to read!

      Yes, but I want this initialization to happen just before run time. There's absolutely no reason, in general, for the initialization of the typical static variable to happen at compile time.

      the lowliest monk

        I'm talking about program run-time, not any file's run-time. If you have a module Foo that uses INIT you'll get a "Too late to run INIT block" warning if you require Foo during program run-time. E.g. you have

        # Foo.pm INIT { print 'Foo' } # foo.pl require Foo;
        That won't execute like one would hope. By using INIT to initialize variables to constants you impose a completely unnecessary constraint on your module. No module that uses your Foo can be loaded at program run-time, meaning you can't ever use Foo, directly or indirectly, in any module that is dynamically loaded (like plugin modules). That's quite a serious limitation.

        There's absolutely no reason, in general, for the initialization of the typical static variable to not happen at compile-time.

        ihb

        See perltoc if you don't know which perldoc to read!

        Since the other argument wasn't convincing enough, here's an argument that hopefully is.

        There's absolutely no reason, in general, for the initialization of the typical static variable to happen at compile time.

        Yes there is. Now, a very real-world example:

        # Foo.pm package Foo; use base 'Exporter'; our @EXPORT = qw/ foo_init foo_begin /; { my $thing; INIT { $thing = 'init' }; sub foo_init { print "init: $thing"; } } { my $thing; BEGIN { $thing = 'begin' }; sub foo_begin { print "begin: $thing"; } } 1; # Bar.pm package Bar; use Foo; # This can be put in &import if you # think that's more real-world. foo_init(); foo_begin(); 1; # foo.pl #!/usr/bin/perl -wl use Bar;
        The output of this will be
        Use of uninitialized value in concatenation (.) or string at Foo.pm li +ne 9. init: begin: begin

        Again, if you put unnecessary INITs in a module you render that module close to useless for many applications where it could've been used.

        ihb

        See perltoc if you don't know which perldoc to read!