Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

static variable hack

by InfiniteLoop (Hermit)
on Oct 29, 2007 at 19:32 UTC ( #647911=perlquestion: print w/replies, xml ) Need Help??

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

Greetings,
I came across this Undefined behavior in Perl ... post by Mark Dominus. This static variable hack really confused me.
Quoting from the article:
sub foo { my $static = 42 if 0; print "static is now $static\n"; $static++; } foo() for 1..5;

results in:
static is now static is now 1 static is now 2 static is now 3 static is now 4
I have checked the perldocs, but couldn't find an explanation for this behaviour. Any enlightenment on this hack is much appreciated.

Replies are listed 'Best First'.
Re: static variable hack
by ikegami (Pope) on Oct 29, 2007 at 19:37 UTC

    When my is encountered at run-time, a directive is placed on the stack to clear the variable. Since you're not executing my, the directive is not placed on the stack, so the variable doesn't get cleared.

    The docs warn against using this side-effect of internal mechanics. (Emphasis in original.)

    Note: The behaviour of a my statement modified with a statement modifier conditional or loop construct (e.g. my $x if ...) is undefined.

    If you wish to have a static variable, use the following. (Surrounding curlies are optional.)

    { my $static; sub func { ... } }

    See recent thread Lexical scope variable is not undef'ed.

      { my $static; sub func { ... } }

      I'd updated that to:

      BEGIN { my $static= ...; sub func { ... } }

      The BEGIN allows this to work just fine under mod_perl, and protects against people calling the subroutine before the $static is initialized. The subroutine is defined when it is compiled, so it is best to initialize the $static before that.

      - tye        

      Right, thanks. Also I have ran this code with "use strict;". If, "my" isn't executed, why doesn't the "strict" complain ?
        Creating the variable is my's compile-time effect. The my gets compiled whether it gets executed or not.
Re: static variable hack
by FunkyMonk (Chancellor) on Oct 29, 2007 at 19:36 UTC
    You won't find an explanation of it it the documentation, because the behaviour is undefined. perlsyn is the best you'll get:

    NOTE: The behaviour of a my statement modified with a statement modifier conditional or loop construct (e.g. my $x if ... ) is undefined. The value of the my variable may be undef, any previously assigned value, or possibly anything else. Don't rely on it. Future versions of perl might do something different from the version of perl you try it out on. Here be dragons.

Re: static variable hack
by shmem (Chancellor) on Oct 29, 2007 at 20:19 UTC
    This line
    my $static = 42 if 0;

    is optimized away after compilation, because the 0 is a constant:

    qwurx [shmem] ~ > perl -MO=Deparse sub foo { my $static = 42 if 0; print "static is now $static\n"; $static++; } foo() for 1..5; __END__ sub foo { '???'; print "static is now $static\n"; $static++; } ; foo foreach (1 .. 5); __DATA__ - syntax OK

    Note the '???' showing a statement swallowed by the optimizer.

    Because optimization happens after compile, the lexical variable declared via my already has been seen and allocated for the subroutine's scope.

    That's why that construct passes strictures. And - that' the hack - because the my declaration isn't seen ever again at runtime, the lexical inside that sub doesn't get cleared on subsequent invocations of the sub.

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}

      Overall right. Just nitpicking two details.

      First, optimization is not a factor. It's simply whether the my gets executed or not.

      Second, you're also off on the timing. Clearing occurs at end of scope. It's triggered by the my, but it doesn't occurs when the my is encountered. (By the way, that's also when a new my variable is created if the refcount is greater than 1.)

      Both points can be observed in

      sub foo { my ($reset) = @_; my $x if $reset; # Will reset at end of scope if $reset is true. return ++$x; } print foo(0), "\n"; # 1 print foo(0), "\n"; # 2 print foo(1), "\n"; # 3 print foo(0), "\n"; # 1 print foo(0), "\n"; # 2
Re: static variable hack
by KurtSchwind (Chaplain) on Oct 29, 2007 at 20:02 UTC
    I guess I'm missing the mystery. You have my $static and it's undef. It's not going to default to 42 because it's not 0. Once you use the unary op ++, it'll cast undef to a number (in this case 0) and then increment it. Maybe I'm missing something here, and if I am, my apologies. --
    I used to drive a Heisenbergmobile, but everyone I looked at the speedometer, I got lost.

      Compare

      sub foo { my $var if 0; $var++; print "var is now $var\n"; }

      and

      sub foo { my $var ; $var++; print "var is now $var\n"; }

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://647911]
Approved by FunkyMonk
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others musing on the Monastery: (6)
As of 2020-06-04 21:17 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Do you really want to know if there is extraterrestrial life?



    Results (35 votes). Check out past polls.

    Notices?