I don't recall any of the discussions of Perl 6 mentioning static variables. There aren't any good ways to get static variables in Perl 5. The best is probably:

{ my $static; BEGIN { $static= "Initial value" } sub usesStatic { # ... } }
but that won't work under mod_perl (and, well, it also sucks quite a bit).

Several times I've mentioned that I'd like to see BEGIN (and a few other similar "keywords") be supported as statement modifiers, in part so that we could have real static variables in Perl:

sub usesStatic { my $static= "Initial value" BEGIN; # ... }
but never with much visibility.

[

Note that this would function quite a bit like

sub usesStatic { my $static if 0; # ... }
but without being a horrid hack that many consider to be bug (and you could provide an initial value and Perl would be smart enough to make $static so that it does "stay shared" if you used nested subroutines for some strange reason such as mod_perl).

]

I really like that the BEGIN makes it clear that the initialization code is going to run at compile time and that you could instead say, for example, CHECK if you want the initialization to happen a bit later.

So I wanted to raise the visibility of this idea. I also was hoping someone had some insight into what plans, if any, there are for static variables in Perl 6. Depending on the feedback I get here, I may post this suggestion to a Perl 6 discussion list.

Note that you could also use this for other things. If there was also a way to use eval without introducing an extra layer of scope, then you could do lots of really fun things akin to source-code macros:

eval q{ conditional code; } if condition BEGIN;
where the "conditional code" could, for example, declare lexicals, which could be really cool (and dangerous).

Update: Note that global variables ("package" variables) are also a form of static variable and they have some advantages ove the "best" version I provided above. They also have some disadvantages (being global), otherwise the "best" version would have never been thought up. Feel free to think "non-global static" or "static lexical" whenever you read "static" above if that helps. (:

        - tye (but my friends call me "Tye")

Replies are listed 'Best First'.
Re: Static variables (and also Perl 6)
by clintp (Curate) on Jan 26, 2002 at 05:13 UTC
    Last week when I read Apocalypse 4 I had terrible visions of what the elimination of "bare blocks" would mean for "static" variable declarations. I wasn't the only one confused, so I wrote a note to Larry and Damian asking that this notion be cleared up in the next exegesis.

    This is the jist of the conversation relating to this topic. Damian: I hope you don't mind the reprinting of your mail, I'm sending a note to you asking forgiveness rather than permission in advance:

    I asked:

    We think (and maybe the Exegesis can clarify) that this means the elimination of two<super>*</super> succinct, obvious, and useful idioms. The declaration of C static-like variables ("compile-time" initializations):
    { my $foo=512; sub something { $foo++; } }
    And other stuff. Damian's reply was:
    That's now:
    for 1 { my $foo=512; sub something { $foo++; } }
    or:
    INIT { my $foo=512; sub something { $foo++; } }
    After I had whined:
    Cluttering up these expressions with do {} and for 1 {} seems like syntatic nonsense and misdirection.
    He said:
    No, it's just a reflection of the fundamental change that a block is now *always* a closure (and hence a value). I actually think that the INIT {...} or even the BEGIN {...} approach is a much safer way to specify such things anyway, as it guarantees that the shared lexical (a lovely idiom, I agree) is initialized before any potential use of the subroutines that share it.
    I hope this sheds a little light on the topic. I know it gave me a little more positive outlook on Exegesis 4.

    <super>*</super>The other I asked about was shared lexicals between subs: { my $foo; sub bar{} sub baz{} }

      Thanks. That is interesting.

      This also resolves one mod_perl problem. mod_perl basically warps each CGI script so that it becomes a subroutine so that it can be called over and over again without having to be recompiled. You can simulate this like so:

      #!/usr/bin/perl -w use strict; sub mod_perl { { my $static1; print "[", defined($static1) ? $static1 : "undef", "] "; BEGIN { $static1= "Hello" } sub sub1 { my $old= $static1; $static1= shift if @_; return $old; } } BEGIN { my $static2= "Hi"; print "<$static2> "; sub sub2 { my $old= $static2; $static2= shift if @_; return $old; } } print "(",sub1(shift),") "; print "(",sub2(shift),")\n"; } mod_perl(qw( Goodbye Bye )); mod_perl(qw( Morning Morn )); mod_perl(qw( Evening Eve )); mod_perl();
      which produces the following output:
      Variable "$static1" will not stay shared at static.pl line 9. <Hi> [Hello] (Hello) (Hi) [undef] (Goodbye) (Bye) [undef] (Morning) (Morn) [undef] (Evening) (Eve)
      which shows that the BEGIN (on the outside) has removed the "won't stayed shared problem".

      Of course, it doesn't solve the ``reinitialization each time the "script" is "rerun"'' problem, but then my proposal didn't address that either.

      And I'd still like to be able to create static variables without so much extra baggage (a whole extra block and having to move the variable outside of the subroutine).

      It'd be nice to be able to put static variable in inner blocks even:

      sub uniqueNonBlanks { my( $avItems )= @_; my @return; for my $item ( @$avItems ) { my %seen= ( "" => 1 ) BEGIN; push @return, $item unless $seen{$item}++; } return wantarray ? @return : \@return; }
      where
      my @a= uniqueNonBlanks("Why","","I","Why"); my @b= uniqueNonBlanks("Why","You","Be","I"); $"= ","; print "(@a) (@b)\n";
      prints "(Why,I) (You,Be)".

      Oh, BTW, some have asked what a static variable is. It is a lexical variable in a subroutine that doesn't get recreated each time the subroutine is called. It keeps its value between successive calls to the subroutine. So, no matter how many times the subroutine gets called, there is only one instance of the static variable.

      Static variables are useful for the same reasons that singleton classes are useful. It is just that a static variable is trivial to implement in comparison to a singleton class.

      If you haven't missed static variables in Perl, then it probably just because you've been using globals for those cases instead.

      Here is a paraphrase of a real-life example of static variables that shows how globals aren't the best replacement:

      sub validateOptions { my( $hvOptions, $hvUserOpts )= @_; for my $key ( keys %$hvOptions ) { $hvOptions->{$key}= delete $hvUserOpts->{$key} if exists $hvUserOpts->{$key}; } if( %$hvUserOpts ) { my $subName= (caller(1))[3]; croak "$subName: Invalid options (", join(",",keys %$hvUserOpts),")"; } return $hvOptions; } BEGIN { my %defaults= ( Access=>READ_ONLY, Delimiter=>"/" ); sub Open { my( $keyName, $hvUserOpts )= @_; my $hvOpts= validOptions( {%defaults}, $hvUserOpts ); # ... } } BEGIN { my %defaults= ( Delimiter=>"/", Translate=>"text" ); sub Read { my( $handle, $hvUserOpts )= @_; my $hvOpts= validOptions( {%defaults}, $hvUserOpts ); # ... } }
      If I used globals I'd have to replace the two %defaults static variables with two globals with different names:
      our %Open_defaults= ( Access=>READ_ONLY, Delimiter=>"/" ); sub Open { my( $keyName, $hvUserOpts )= @_; my $hvOpts= validOptions( {%Open_defaults}, $hvUserOpts ); # ... } our %Read_defaults= ( Delimiter=>"/", Translate=>"text" ); sub Read { my( $handle, $hvUserOpts )= @_; my $hvOpts= validOptions( {%Read_defaults}, $hvUserOpts ); # ... }
      which makes the code harder to modularize and maintain.

      So I'd still like BEGIN as a statement modifier...

      But what about the other mod_perl problem. The current way to solve that is only use globals:

      sub mod_perl { our $static= "Hi"; sub sub1 { my $old= $static1; $static1= shift if @_; return $old; } # ... }
      because now the initialization will be done each time the "script" is "rerun", that is, each time mod_perl() is called. And we won't get "won't stay shared" problems because globals are static; there is only ever one instance of a global variable, so that instance is always the one that is shared.

      But we'd rather not use globals if we can avoid them so that we don't have to worry about collisions in the names of two static variables from far-flung ends of the same package.

      So we'd really like something that works like:

      sub mod_perl { { my $static1 BEGIN; $static1= "Hi"; sub sub1 { my $old= $static1; $static1= shift if @_; return $old; } } # ... }
      but it'd be even cooler to be able to write that as:
      sub mod_perl { sub sub1 { my $static1= "Hi" STATIC; my $old= $static1; $static1= shift if @_; return $old; } # ... }
      where STATIC tells Perl to create an instance of $static1 only once (at compile time) but to reinitialize that variable each time the run-time pass hits the definition of "sub sub1". Currently, the definition of "sub sub1" doesn't even exist once we get to "run time". But the presense of a STATIC variable inside of a nested subroutine would tell Perl to replace the "sub sub1" definition with $static1= "Hi" in the compiled byte code. (If the subroutine was not nested, then the STATIC variable would simply be initialized at compile time and no run-time code would be generated.)

              - tye (but my friends call me "Tye")
        Try this out:
        my $static := BEGIN {my $foo = "default value"};
        If I am not mistaken, the BEGIN block should initialize its variable at compile time, and always return the same variable thereafter. The my variable that you are declaring is then made an alias to this returned variable. Because it is declared lexically, it is available in a lexical scope only.

        If that doesn't work, then some fairly straightforward variant on it should.

        This construct is embeddable in any scope you want. And so you can embed it in inner blocks as well. Figure out how to add syntactic sugar, and spice to taste. :-)

Re: Static variables (and also Perl 6)
by Juerd (Abbot) on Jan 26, 2002 at 01:29 UTC
    Can someone please explain to me why static variables are so important? I never felt any need for static variables. Closures and OO are so much cooler.

    2;0 juerd@ouranos:~$ perl -e'undef christmas' Segmentation fault 2;139 juerd@ouranos:~$

Re: Static variables (and also Perl 6)
by Juerd (Abbot) on Jan 26, 2002 at 22:07 UTC
    Some have tried to explain why static variables are good. I understand it's needed to preserve state, but what's so wrong about the closures we're using right now? ({ my $foo = 3; sub { ... } }) Maybe some filter can provide some syntactic sugar, because that's what this seems to be all about.

    I haven't seen Tie::Static in this discussion yet - is tie not good enough?

    Update - Putting money where mouth is - I created a filter :)
    Filter::Static
      Note that with Perl 6 we can use := to do what I did with a tie, resulting in the same idea but without most of the overhead.
Re: Static variables (and also Perl 6)
by ignatz (Vicar) on Jan 26, 2002 at 01:45 UTC
    That's a very Perlish way to think of it. Interesting.