rovf has asked for the wisdom of the Perl Monks concerning the following question:

Assuming I have a sub and this sub needs a variable which should have persistent value from call to call, i.e. something like in C++

// This is C++ void f() { static int myvar=myfunc(); // will be initialized only at the first +call of f() ... g(++myvar); // Incremented on every call }
In Perl I have found the following solution to this problem:
sub f { our $myval; BEGIN { $myval=myfunc() }; ... g(++$myval); }
It is not 100% equivalent to the C++ example, because $myval is not really private to f. If another sub in the same package would also use our $myval, it would denote the same variable.

My questions are now:

-- 
Ronald Fischer <ynnor@mm.st>

Replies are listed 'Best First'.
Re: Initialization of "local static" (style question)
by Corion (Patriarch) on Feb 03, 2009 at 09:56 UTC

    If you want $myval to be private to &f, don't use our, use my in a block enclosing both, &f and $myval:

    { my $myval = myfunc(); sub f { ... }; };

    Alternatively, if you are on Perl 5.10, you can use the new state keyword, which is basically the same but a bit more explicit. Also see About "state" variables in Perl 5.10 for some more discussion, also about the timing of the different initializations.

      use my in a block enclosing both

      I had thought that my function would not be visible outside the block then, but of course, functions are always global. Nice idea!

      I will remember it for use in a later project, though, because in my current one, the automatic documentation system requires that the documentation of a function appears immediately before the line starting with 'sub', which means that I would have to move the declaration of $myval in front of the function docs.

      -- 
      Ronald Fischer <ynnor@mm.st>
        One option would be to use closures.
        ## DOC: returns a function that does that and that. sub ff { my $myval=myfunc(); ... sub { g(++$myval) } } ... my $f = ff; ... my $x = $f->();
        []s, HTH, Massa (κς,πμ,πλ)
      The critical thing to remember about the closure trick in 5.8 (I'm not familiar with 5.10) is that  my variables are not initialized until runtime. This is touched on in About "state" variables in Perl 5.10. Making the closure blocks  BEGIN or  INIT blocks in 5.8 controls this, but you still must consider block ordering. See perlmod.

      Examples run under 5.8.2.

      >perl -wMstrict -le "print F(); { my $y = X(); sub F { return $y } } { my $x = 'foo'; sub X { return $x } } " Use of uninitialized value in print at -e line 1. >perl -wMstrict -le "print F(); BEGIN { my $y = X(); sub F { return $y } } BEGIN { my $x = 'foo'; sub X { return $x } } " Undefined subroutine &main::X called at -e line 1. BEGIN failed--compilation aborted at -e line 1. >perl -wMstrict -le "print F(); BEGIN { my $x = 'foo'; sub X { return $x } } BEGIN { my $y = X(); sub F { return $y } } " foo >perl -wMstrict -le "print F(); INIT { my $y = X(); sub F { return $y } } INIT { my $x = 'foo'; sub X { return $x } } " Use of uninitialized value in print at -e line 1. >perl -wMstrict -le "print F(); INIT { my $x = 'foo'; sub X { return $x } } INIT { my $y = X(); sub F { return $y } } " foo
      massa's function generator approach of Re^3: Initialization of "local static" (style question) gets around some of this.
Re: Initialization of "local static" (style question)
by JavaFan (Canon) on Feb 03, 2009 at 10:43 UTC
    In a modern Perl (like one released in 2007), I would use 'state' to get a static variable:
    sub f { state $myval = myfunc (); ... g(++$myval); }

      I hadn't known about state, but since the code must be run on 5.8.8, this is not an option yet.

      -- 
      Ronald Fischer <ynnor@mm.st>