Softpanorama

May the source be with you, but remember the KISS principle ;-)
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

News

Best Books

Recommended Links  Perl state variables  Perl our variables My Variables Local variables

Debugging

Namespaces Table of Contents           Perl Regular Expressions

 

Libraries

Perl modules

Perl Warts

Perl philosophy and history Tips Humor Etc

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

Syntax rules

state VARLIST 

  • state TYPE VARLIST
  • state VARLIST : ATTRS
  • state TYPE VARLIST : ATTRS

    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.

    One time initialization of state variables

    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, };


  • Top Visited
    Switchboard
    Latest
    Past week
    Past month

    NEWS CONTENTS

    Old News ;-)

    [Nov 23, 2019] Static local variables in Perl

    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 a state 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 for womble .

    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
    10
    

    Even 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
    10
    

    Otherwise, 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. 147

    zoul ,

    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 complete ikegami '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"; }
    } # local
    

    The 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 if exit is removed and a show2 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"; }
    } # local
    

    And now the output what was expected:

    After Crying
    Solaris
    

    But state in 5.10+ is a better choice...

    I hope this helps!

    [Oct 09, 2019] Static and state variables in Perl

    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
    1. use strict ;
    2. use warnings ;
    3. use 5.010 ;
    4. sub count {
    5. state $counter = 0 ;
    6. $counter ++;
    7. return $counter ;
    8. }
    9. say count ();
    10. say count ();
    11. say count ();
    12. #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
    3
    

    If 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 call

    Check out this strange example:

    1. use strict ;
    2. use warnings ;
    3. use 5.010 ;
    4. sub count {
    5. state $counter = say "world" ;
    6. $counter ++;
    7. return $counter ;
    8. }
    9. say "hello" ;
    10. say count ();
    11. say count ();
    12. say count ();

    This will print out

    hello
    world
    2
    3
    4
    

    showing 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
    1. use strict ;
    2. use warnings ;
    3. use 5.010 ;
    4. {
    5. my $counter = 0 ;
    6. sub count {
    7. $counter ++;
    8. return $counter ;
    9. }
    10. }
    11. say count ();
    12. say count ();
    13. 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
    1. use strict ;
    2. use warnings ;
    3. use 5.010 ;
    4. say "hi" ;
    5. {
    6. my $counter = say "world" ;
    7. sub count {
    8. $counter ++;
    9. return $counter ;
    10. }
    11. }
    12. say "hello" ;
    13. say count ();
    14. say count ();
    15. say count ();
    hi
    world
    hello
    2
    3
    4
    

    This 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 variable

    This "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:

    1. use strict ;
    2. use warnings ;
    3. use 5.010 ;
    4. {
    5. my $counter = 0 ;
    6. sub count {
    7. $counter ++;
    8. return $counter ;
    9. }
    10. sub reset_counter {
    11. $counter = 0 ;
    12. }
    13. }
    14. say count ();
    15. say count ();
    16. say count ();
    17. reset_counter ();
    18. say count ();
    19. say count ();
    1
    2
    3
    1
    2
    

    Now both functions can access the $counter variable, but still nothing outside the enclosing block can access it.

    Static arrays and hashes

    As 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:

    1. use strict ;
    2. use warnings ;
    3. use 5.010 ;
    4. sub fib {
    5. state @y ;
    6. @y = ( 1 , 1 ) if not @y ; # workaround initialization
    7. push @y , $y [ 0 ]+ $y [ 1 ];
    8. return shift @y ;
    9. }
    10. say fib ();
    11. say fib ();
    12. say fib ();
    13. say fib ();
    14. say fib ();

    Alternatively we could use the "old-style" static variable with the enclosing block.

    Here is the example generating the Fibonacci series:

    1. use strict ;
    2. use warnings ;
    3. use 5.010 ;
    4. {
    5. my @y = ( 1 , 1 );
    6. sub fib {
    7. push @y , $y [ 0 ]+ $y [ 1 ];
    8. return shift @y ;
    9. }
    10. }
    11. say fib ();
    12. say fib ();
    13. say fib ();
    14. say fib ();
    15. say fib ();

    [Aug 26, 2019] Static and state variables in Perl

    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
    1. use strict ;
    2. use warnings ;
    3. use 5.010 ;
    4. sub count {
    5. state $counter = 0 ;
    6. $counter ++;
    7. return $counter ;
    8. }
    9. say count ();
    10. say count ();
    11. say count ();
    12. #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
    3
    

    If 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 call

    Check out this strange example:

    1. use strict ;
    2. use warnings ;
    3. use 5.010 ;
    4. sub count {
    5. state $counter = say "world" ;
    6. $counter ++;
    7. return $counter ;
    8. }
    9. say "hello" ;
    10. say count ();
    11. say count ();
    12. say count ();

    This will print out

    hello
    world
    2
    3
    4
    

    showing 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
    1. use strict ;
    2. use warnings ;
    3. use 5.010 ;
    4. {
    5. my $counter = 0 ;
    6. sub count {
    7. $counter ++;
    8. return $counter ;
    9. }
    10. }
    11. say count ();
    12. say count ();
    13. 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
    1. use strict ;
    2. use warnings ;
    3. use 5.010 ;
    4. say "hi" ;
    5. {
    6. my $counter = say "world" ;
    7. sub count {
    8. $counter ++;
    9. return $counter ;
    10. }
    11. }
    12. say "hello" ;
    13. say count ();
    14. say count ();
    15. say count ();
    hi
    world
    hello
    2
    3
    4
    

    This 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 variable

    This "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:

    1. use strict ;
    2. use warnings ;
    3. use 5.010 ;
    4. {
    5. my $counter = 0 ;
    6. sub count {
    7. $counter ++;
    8. return $counter ;
    9. }
    10. sub reset_counter {
    11. $counter = 0 ;
    12. }
    13. }
    14. say count ();
    15. say count ();
    16. say count ();
    17. reset_counter ();
    18. say count ();
    19. say count ();
    1
    2
    3
    1
    2
    

    Now both functions can access the $counter variable, but still nothing outside the enclosing block can access it.

    Static arrays and hashes

    As 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:

    1. use strict ;
    2. use warnings ;
    3. use 5.010 ;
    4. sub fib {
    5. state @y ;
    6. @y = ( 1 , 1 ) if not @y ; # workaround initialization
    7. push @y , $y [ 0 ]+ $y [ 1 ];
    8. return shift @y ;
    9. }
    10. say fib ();
    11. say fib ();
    12. say fib ();
    13. say fib ();
    14. say fib ();

    Alternatively we could use the "old-style" static variable with the enclosing block.

    Here is the example generating the Fibonacci series:

    1. use strict ;
    2. use warnings ;
    3. use 5.010 ;
    4. {
    5. my @y = ( 1 , 1 );
    6. sub fib {
    7. push @y , $y [ 0 ]+ $y [ 1 ];
    8. return shift @y ;
    9. }
    10. }
    11. say fib ();
    12. say fib ();
    13. say fib ();
    14. say fib ();

    Recommended Links

    Google matched content

    Softpanorama Recommended

    Top articles

    Sites