|
Home | Switchboard | Unix Administration | Red Hat | TCP/IP Networks | Neoliberalism | Toxic Managers |
(slightly skeptical) Educational society promoting "Back to basics" movement against IT overcomplexity and bastardization of classic Unix |
Perl state variables are close replica of PL/1 static variables: they are initialized only once. For some reason Perl language designer decide to avoid including the word "static" in Perl lexicon. May be because in reality they are still allocated on the heap not at compile time like a real static variables :-)
State variable are locally scoped: they are visible only in the block they are declared and inner blocks.
If you do not need local scope you can use our variables instead. Which are also initialized once, when you initialize the modules in which they are declared.
State variable are available only since Perl 5.10 and require explicit use "use v.5.10" (or later version ) statement to be activated. That means that to enable them, you need to declare that you're using a version of Perl that's at least v5.10, for example
use v.5.10
state VARLIST
state
declares
a lexically scoped variable, just like
my
. However, those variables
will never be reinitialized, contrary to lexical variables that are reinitialized each time
their enclosing block is entered. See
Persistent
Private Variables in perlsub for details.
If more than one variable is listed, the list must be placed in parentheses. With a parenthesized
list, undef
can be used as a dummy placeholder. However, since initialization of state variables in list context
is currently not possible this would serve no purpose.
state
variables
are enabled only when the
use feature "state"
pragma is in effect, unless the keyword is written as CORE::state
. See also
feature. Alternately, include a
use v5.10
or later
to the current scope.
Unlike other variable declarations, initialization of state variables is restricted to simple scalar variables only.
Since version 5.10 of Perl you can simply use the
state
feature instead
of closures. The main point with state variables is that you don't have to use a BEGIN (or UNITCHECK
) block to make sure that the initialization happens before the function is called and only once.
For example:
use v5.14; sub incr_x { state $x = 10; # initialization is performed only on the first invocation return $x++; }
That function will now behave like a simple generator returning first 10, then 11, then 12, and so on.
Here's an example when it used to keep a private counter if each item:
sub seen_count {
state %count; my $item = shift(); return ++$count{$item}; }
You can still use arrays and hashes as state variables, but you can't magically initialize them the way you can with scalars. This isn't actually the limitation it might appear to be, because you can always store a reference to the type you want, and that is a scalar. For example, instead of: # can't use state %hash = (....) my %hash = ( READY => 1, WILLING => 1, ABLE => 1, ); as a state variable, you would use: state $hashref = { READY => 1, WILLING => 1, ABLE => 1, };
|
Switchboard | ||||
Latest | |||||
Past week | |||||
Past month |
Jan 01, 2012 | stackoverflow.com
Ask Question Asked 7 years, 5 months ago Active 2 years, 8 months ago Viewed 12k times
Charles , 2012-05-31 20:50:19
I'm looking for advice on Perl best practices. I wrote a script which had a complicated regular expression:my $regex = qr/complicated/; # ... sub foo { # ... if (/$regex/) # ... }where
foo
is a function which is called often, and$regex
is not used outside that function. What is the best way to handle situations like this? I only want it to be interpreted once, since it's long and complicated. But it seems a bit questionable to have it in global scope since it's only used in that sub. Is there a reasonable way to declare it static?A similar issue arises with another possibly-unjustified global. It reads in the current date and time and formats it appropriately. This is also used many times, and again only in one function. But in this case it's even more important that it not be re-initialized, since I want all instances of the date-time to be the same from a given invocation of the script, even if the minutes roll over during execution.
At the moment I have something like
my ($regex, $DT); sub driver { $regex = qr/complicated/; $DT = dateTime(); # ... } # ... driver();which at least slightly segregates it. But perhaps there are better ways.
Again: I'm looking for the right way to do this, in terms of following best practices and Perl idioms. Performance is nice but readability and other needs take priority if I can't have everything.
hobbs ,
If you're using perl 5.10+, use astate
variable.use feature 'state'; # use 5.010; also works sub womble { state $foo = something_expensive(); return $foo ** 2; }will only call
something_expensive
once.If you need to work with older perls, then use a lexical variable in an outer scope with an extra pair of braces:
{ my $foo = something_expensive(); sub womble { return $foo ** 2; } }this keeps
$foo
from leaking to anyone except forwomble
.ikegami , 2012-05-31 21:14:04
Is there any interpolation in the pattern? If not, the pattern will only be compiled once no matter how many times the qr// is executed.$ perl -Mre=debug -e'qr/foo/ for 1..10' 2>&1 | grep Compiling | wc -l 1 $ perl -Mre=debug -e'qr/foo$_/ for 1..10' 2>&1 | grep Compiling | wc -l 10Even if there is interpolation, the pattern will only be compiled if the interpolated variables have changed.
$ perl -Mre=debug -e'$x=123; qr/foo$x/ for 1..10;' 2>&1 | grep Compiling | wc -l 1 $ perl -Mre=debug -e'qr/foo$_/ for 1..10' 2>&1 | grep Compiling | wc -l 10Otherwise, you can use
{ my $re = qr/.../; sub foo { ... /$re/ ... } }or
use feature qw( state ); sub foo { state $re = qr/.../; ... /$re/ ... }Alan Rocker , 2014-07-02 16:25:27
Regexes can be specified with the "o" modifier, which says "compile pattern once only" - in the 3rd. edition of the Camel, see p. 147zoul ,
There's a state keyword that might be a good fit for this situation:sub foo { state $regex = /.../; ... }TrueY , 2015-01-23 10:14:12
I would like to completeikegami
's great answer. Some more words I would like to waste on the definition of local variables in pre 5.10 perl .Let's see a simple example code:
#!/bin/env perl use strict; use warnings; { # local my $local = "After Crying"; sub show { print $local,"\n"; } } # local sub show2; show; show2; exit; { # local my $local = "Solaris"; sub show2 { print $local,"\n"; } } # localThe user would expect that both
sub
will print the local variable, but this is not true!Output:
After Crying Use of uninitialized value $local in print at ./x.pl line 20.The reason is that
show2
is parsed, but the initialization of the local variable is not executed! (Of course ifexit
is removed and ashow2
is added at the end,Solaris
will be printed in the thirds line)This can be fixed easily:
{ # local my $local; BEGIN { $local = "Solaris"; } sub show2 { print $local,"\n"; } } # localAnd now the output what was expected:
After Crying SolarisBut
state
in 5.10+ is a better choice...I hope this helps!
Oct 09, 2019 | perlmaven.com
Prev Next In most of the cases we either want a variable to be accessible only from inside a small scope, inside a function or even inside a loop. These variables get created when we enter the function (or the scope created by a a block) and destroyed when we leave the scope.In some cases, especially when we don't want to pay attention to our code, we want variables to be global, to be accessible from anywhere in our script and be destroyed only when the script ends. In General having such global variables is not a good practice.
In some cases we want a variable to stay alive between function calls, but still to be private to that function. We want it to retain its value between calls.
Are you serious about Perl? Check out my Beginner Perl Maven book .
I have written it for you!In the C programming language one can designate a variable to be a static variable . This means it gets initialized only once and it sticks around retaining its old value between function calls.
In Perl, the same can be achieved using the state variable which is available starting from version 5.10, but there is a construct that will work in every version of Perl 5. In a way it is even more powerful.
Let's create a counter as an example:
state variable
- use strict ;
- use warnings ;
- use 5.010 ;
- sub count {
- state $counter = 0 ;
- $counter ++;
- return $counter ;
- }
- say count ();
- say count ();
- say count ();
- #say $counter;
In this example, instead of using my to declare the internal variable , we used the state keyword.
$counter is initialized to 0 only once, the first time we call counter() . In subsequent calls, the line state $counter = 0; does not get executed and $counter has the same value as it had when we left the function the last time.Thus the output will be:
1 2 3If we removed the # from last line, it would generate a Global symbol "$counter" requires explicit package name at ... line ... error when trying to compile the script. This just shows that the variable $counter is not accessible outside the function.
state is executed in the first callCheck out this strange example:
- use strict ;
- use warnings ;
- use 5.010 ;
- sub count {
- state $counter = say "world" ;
- $counter ++;
- return $counter ;
- }
- say "hello" ;
- say count ();
- say count ();
- say count ();
This will print out
hello world 2 3 4showing that the state $counter = say "world"; line only gets executed once. In the first call to count() say , which was also added in version 5.10 , will return 1 upon success.
static variables in the "traditional" way
- use strict ;
- use warnings ;
- use 5.010 ;
- {
- my $counter = 0 ;
- sub count {
- $counter ++;
- return $counter ;
- }
- }
- say count ();
- say count ();
- say count ();
This provides the same result as the above version using state , except that this could work in older versions of perl as well. (Especially if I did not want to use the say keyword, that was also introduced in 5.10.)
This version works because functions declarations are global in perl - so count() is accessible in the main body of the script even though it was declared inside a block. On the other hand the variable $counter is not accessible from the outside world because it was declared inside the block. Lastly, but probably most importantly, it does not get destroyed when we leave the count() function (or when the execution is outside the block), because the existing count() function still references it.
Thus $count is effectively a static variable.
First assignment time
- use strict ;
- use warnings ;
- use 5.010 ;
- say "hi" ;
- {
- my $counter = say "world" ;
- sub count {
- $counter ++;
- return $counter ;
- }
- }
- say "hello" ;
- say count ();
- say count ();
- say count ();
hi world hello 2 3 4This shows that in this case too, the declaration and the initial assignment my $counter = say "world"; happens only once, but we can also see that the assignment happens before the first call to count() as if the my $counter = say "world"; statement was part of the control flow of the code outside of the block.
Shared static variableThis "traditional" or "home made" static variable has an extra feature. Because it does not belong to the the count() subroutine, but to the block surrounding it, we can declare more than one functions in that block and we can share this static variable between two or even more functions.
For example we could add a reset_counter() function:
- use strict ;
- use warnings ;
- use 5.010 ;
- {
- my $counter = 0 ;
- sub count {
- $counter ++;
- return $counter ;
- }
- sub reset_counter {
- $counter = 0 ;
- }
- }
- say count ();
- say count ();
- say count ();
- reset_counter ();
- say count ();
- say count ();
1 2 3 1 2Now both functions can access the $counter variable, but still nothing outside the enclosing block can access it.
Static arrays and hashesAs of now, you cannot use the state declaration in list context. This means you cannot write state @y = (1, 1); . This limitation could be overcome by some extra coding. For example in this implementation of the Fibonacci series, we checked if the array is empty and set the default values:
- use strict ;
- use warnings ;
- use 5.010 ;
- sub fib {
- state @y ;
- @y = ( 1 , 1 ) if not @y ; # workaround initialization
- push @y , $y [ 0 ]+ $y [ 1 ];
- return shift @y ;
- }
- say fib ();
- say fib ();
- say fib ();
- say fib ();
- say fib ();
Alternatively we could use the "old-style" static variable with the enclosing block.
Here is the example generating the Fibonacci series:
- use strict ;
- use warnings ;
- use 5.010 ;
- {
- my @y = ( 1 , 1 );
- sub fib {
- push @y , $y [ 0 ]+ $y [ 1 ];
- return shift @y ;
- }
- }
- say fib ();
- say fib ();
- say fib ();
- say fib ();
- say fib ();
Aug 26, 2019 | perlmaven.com
In most of the cases we either want a variable to be accessible only from inside a small scope, inside a function or even inside a loop. These variables get created when we enter the function (or the scope created by a a block) and destroyed when we leave the scope.
In some cases, especially when we don't want to pay attention to our code, we want variables to be global, to be accessible from anywhere in our script and be destroyed only when the script ends. In General having such global variables is not a good practice.
In some cases we want a variable to stay alive between function calls, but still to be private to that function. We want it to retain its value between calls.
Are you serious about Perl? Check out my Beginner Perl Maven book .
I have written it for you!In the C programming language one can designate a variable to be a static variable . This means it gets initialized only once and it sticks around retaining its old value between function calls.
In Perl, the same can be achieved using the state variable which is available starting from version 5.10, but there is a construct that will work in every version of Perl 5. In a way it is even more powerful.
Let's create a counter as an example:
state variable
- use strict ;
- use warnings ;
- use 5.010 ;
- sub count {
- state $counter = 0 ;
- $counter ++;
- return $counter ;
- }
- say count ();
- say count ();
- say count ();
- #say $counter;
In this example, instead of using my to declare the internal variable , we used the state keyword.
$counter is initialized to 0 only once, the first time we call counter() . In subsequent calls, the line state $counter = 0; does not get executed and $counter has the same value as it had when we left the function the last time.Thus the output will be:
1 2 3If we removed the # from last line, it would generate a Global symbol "$counter" requires explicit package name at ... line ... error when trying to compile the script. This just shows that the variable $counter is not accessible outside the function.
state is executed in the first callCheck out this strange example:
- use strict ;
- use warnings ;
- use 5.010 ;
- sub count {
- state $counter = say "world" ;
- $counter ++;
- return $counter ;
- }
- say "hello" ;
- say count ();
- say count ();
- say count ();
This will print out
hello world 2 3 4showing that the state $counter = say "world"; line only gets executed once. In the first call to count() say , which was also added in version 5.10 , will return 1 upon success.
static variables in the "traditional" way
- use strict ;
- use warnings ;
- use 5.010 ;
- {
- my $counter = 0 ;
- sub count {
- $counter ++;
- return $counter ;
- }
- }
- say count ();
- say count ();
- say count ();
This provides the same result as the above version using state , except that this could work in older versions of perl as well. (Especially if I did not want to use the say keyword, that was also introduced in 5.10.)
This version works because functions declarations are global in perl - so count() is accessible in the main body of the script even though it was declared inside a block. On the other hand the variable $counter is not accessible from the outside world because it was declared inside the block. Lastly, but probably most importantly, it does not get destroyed when we leave the count() function (or when the execution is outside the block), because the existing count() function still references it.
Thus $count is effectively a static variable.
First assignment time
- use strict ;
- use warnings ;
- use 5.010 ;
- say "hi" ;
- {
- my $counter = say "world" ;
- sub count {
- $counter ++;
- return $counter ;
- }
- }
- say "hello" ;
- say count ();
- say count ();
- say count ();
hi world hello 2 3 4This shows that in this case too, the declaration and the initial assignment my $counter = say "world"; happens only once, but we can also see that the assignment happens before the first call to count() as if the my $counter = say "world"; statement was part of the control flow of the code outside of the block.
Shared static variableThis "traditional" or "home made" static variable has an extra feature. Because it does not belong to the the count() subroutine, but to the block surrounding it, we can declare more than one functions in that block and we can share this static variable between two or even more functions.
For example we could add a reset_counter() function:
- use strict ;
- use warnings ;
- use 5.010 ;
- {
- my $counter = 0 ;
- sub count {
- $counter ++;
- return $counter ;
- }
- sub reset_counter {
- $counter = 0 ;
- }
- }
- say count ();
- say count ();
- say count ();
- reset_counter ();
- say count ();
- say count ();
1 2 3 1 2Now both functions can access the $counter variable, but still nothing outside the enclosing block can access it.
Static arrays and hashesAs of now, you cannot use the state declaration in list context. This means you cannot write state @y = (1, 1); . This limitation could be overcome by some extra coding. For example in this implementation of the Fibonacci series, we checked if the array is empty and set the default values:
- use strict ;
- use warnings ;
- use 5.010 ;
- sub fib {
- state @y ;
- @y = ( 1 , 1 ) if not @y ; # workaround initialization
- push @y , $y [ 0 ]+ $y [ 1 ];
- return shift @y ;
- }
- say fib ();
- say fib ();
- say fib ();
- say fib ();
- say fib ();
Alternatively we could use the "old-style" static variable with the enclosing block.
Here is the example generating the Fibonacci series:
- use strict ;
- use warnings ;
- use 5.010 ;
- {
- my @y = ( 1 , 1 );
- sub fib {
- push @y , $y [ 0 ]+ $y [ 1 ];
- return shift @y ;
- }
- }
- say fib ();
- say fib ();
- say fib ();
- say fib ();
Google matched content |