in reply to Re: Static variables (and also Perl 6)
in thread Static variables (and also Perl 6)
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:
which produces the following output:#!/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 shows that the BEGIN (on the outside) has removed the "won't stayed shared problem".Variable "$static1" will not stay shared at static.pl line 9. <Hi> [Hello] (Hello) (Hi) [undef] (Goodbye) (Bye) [undef] (Morning) (Morn) [undef] (Evening) (Eve)
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:
wheresub uniqueNonBlanks { my( $avItems )= @_; my @return; for my $item ( @$avItems ) { my %seen= ( "" => 1 ) BEGIN; push @return, $item unless $seen{$item}++; } return wantarray ? @return : \@return; }
prints "(Why,I) (You,Be)".my @a= uniqueNonBlanks("Why","","I","Why"); my @b= uniqueNonBlanks("Why","You","Be","I"); $"= ","; print "(@a) (@b)\n";
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:
If I used globals I'd have to replace the two %defaults static variables with two globals with different names: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 ); # ... } }
which makes the code harder to modularize and maintain.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 ); # ... }
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:
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.sub mod_perl { our $static= "Hi"; sub sub1 { my $old= $static1; $static1= shift if @_; return $old; } # ... }
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:
but it'd be even cooler to be able to write that as:sub mod_perl { { my $static1 BEGIN; $static1= "Hi"; sub sub1 { 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")sub mod_perl { sub sub1 { my $static1= "Hi" STATIC; my $old= $static1; $static1= shift if @_; return $old; } # ... }
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
I think this would be a static in Perl 6?
by tilly (Archbishop) on Jan 27, 2002 at 22:59 UTC | |
by TheDamian (Vicar) on Apr 10, 2002 at 00:56 UTC |