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

Given this code:
use strict sub foo { bar(1); bar(2); bar(4); } sub bar { print $_[0] . "bar----------\n"; my $x = 0 if 1 == 2; defined $x ? print $x : print '$x und'; print "\n"; my $y; $y = 0 if 1 == 2; defined $y ? print $y : print '$y und'; print "\n"; $x = $_[0]; $y = $_[0]; bar(3) if $_[0] == 2; } foo();
I get this:
1bar---------- $x und $y und 2bar---------- 1 $y und 3bar---------- $x und $y und 4bar---------- 2 $y und
I'm not very familiar with perl but this result doesn't really mesh with my idea of possible scoping rules for "my". My understanding of what's going on is that when the declaration of $x fails, $x retains the value from the previous call to bar(). This implies a 'static local'-like scope. However, this breaks down when the recursive call does not produce a similar result. If anyone can clear my understanding up, I would appreciate it. As shown with $y, it's easy to work around this issue, but I'd rather have a clearer understanding of the scoping.

Replies are listed 'Best First'.
Re: Confusion over scope of "my" vars
by ikegami (Patriarch) on Nov 26, 2008 at 17:53 UTC

    The behaviour of

    my $x = 0 if 1 == 2;

    is documented as undefined.

    The problem is that you get the compile-time effect of my (declaring the variable) without the run-time effect (clearing the variable).

    Lexicals variables are permanently allocated. They are cleared on scope exit, not freed.

    The recursive effects are related to existence of a copy of the lexicals for every layer of recursion.

    sub f { my ($n) = @_; my $x if 0; print ++$x, "\n"; f($n-1) if $n>1; } f(3); # 1,1,1 f(2); # 2,2 f(3); # 3,3,2

    Update: Added bit about recursion.

Re: Confusion over scope of "my" vars
by almut (Canon) on Nov 26, 2008 at 18:01 UTC
Re: Confusion over scope of "my" vars
by JavaFan (Canon) on Nov 26, 2008 at 18:02 UTC
    How it works for your version of Perl is just a quirk of the implementation. People have used it to make 'static' variables, but that doesn't work as soon as you recurse.

    In 5.10, there are static variables, introduced with keyword 'state'.

    use 5.010; sub blabla { state $x = 0; say ++$x; } blabla; blabla; __END__ 1 2
    Note that in 5.10, my $x if 1 == 2 gives a warning.
Re: Confusion over scope of "my" vars
by Anonymous Monk on Nov 26, 2008 at 18:16 UTC

    I have an interpretation for your results but no time for a formal proove.

    At compiletime the pads for the lexicals $x and $y are associated to the sub. With a recursiv call perl has to allocate a new pad for the function, instead of reusing the old one.

    Furthermore the if-branches are optimised away, so no "my $x" is executed at runtime to resetting $x to undef, so your accessing in 2 and 4 the last setting in the same level.

    in short, it's one of these strange side effects of optimising code away, using B:Deparse you will most probably code-chunks missing.

    you can also try this, which results in an error

    goto label; if (0) { label: print "huhu"; }
    (untested)

    so be aware of optimised code-chunks.

      ups I wasn't logged in...

      UPDATE: you may want to use B::Deparse and B::Concise and the debugger to see what actually happens!

      Anyway I'm not sure why perl doesn't reset the lexical pad to undef when leaving the sub, might be a bug or a necessity for closures.

      If I were you, I'd report this code to perlporters most likely they already discussed it!

      > you can also try this, which results in an error

      I know it's documented but I'm not happy about this behaviour!

        Anyway I'm not sure why perl doesn't reset the lexical pad to undef when leaving the sub
        Well, that's quite obvious. "Resetting" variables that go out of scope would be waste of resources. You'd spend time setting a value for a variable that has no references to it left.

        What's the point?

Re: Confusion over scope of "my" vars
by mikelieman (Friar) on Nov 26, 2008 at 17:56 UTC
    That works without a semi-colon on the 'use strict' line?