in reply to foreach localizing variables

Scoping, compile time / run time, and global / my issues. my variables are located in space, local variables in time. Package variables are "grandfather local" variables - see my/local, space/time (was: Re: The difference between my and local).

Your code commented:

my $value = "four"; # lexical variable my @array = ( "one", "two", "three" ); foreach $value (@array) { # variable $value inside the loop is set # to each element of @array at runtime print "foreach value: $value\t"; function(); } # outer scope lexical $value visible here sub function { # outer scope lexical $value visible here # with its initial value print "function value: $value\n"; }

Had you used a package global throughout, the outcome would have been different:

$value = "four"; my @array = ( "one", "two", "three" ); foreach $value (@array) { print "foreach value: $value\t"; function(); } sub function { print "function value: $value\n"; } __END__ foreach value: one function value: one foreach value: two function value: two foreach value: three function value: three

What about allocating a sub in a block's scope? Let's look at this weird construct:

my $value = "four"; my @array = ( "one", "two", "three" ); foreach $value (@array) # note outer $value variable { print "foreach value: $value\t"; function(); sub function { print "function value: $value\n"; } } __END__ foreach value: one function value: four foreach value: two function value: four foreach value: three function value: four

The result is the same, although the sub is allocated inside the for() block scope. Why? Because the sub, on compilation, gets the outer $value, whereas the loop iteration variable is an alias to the outer.

But what about that?

my $value = "four"; my @array = ( "one", "two", "three" ); foreach my $value (@array) { print "foreach value: $value\t"; function(); sub function { print "function value: $value\n"; } } __END__ foreach value: one function value: foreach value: two function value: foreach value: three function value:

How come? Declaring the loop variable as a my variable to the loop block, the inner loop gets that at compile time, and closes over it (it's a closure), and this variable is initialized empty (assignment happens at run time). The inner sub variable is different from the aliased loop variable.

All this is presented here with a lot of handwaving. The perl sources might provide a clue about what's really happening. Pass arguments to your subroutines to be save.

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

Replies are listed 'Best First'.
Re^2: foreach localizing variables
by AndyJ (Initiate) on Feb 07, 2008 at 11:51 UTC
    Thanks for all the explanations.

    Should have mentioned it's not actually my code! I've fixed it up, but just wanted to understand why it's doing what it's doing.

    I'm still a bit confused though...

    I get the fact that the compile time of the subroutine means it will use the initial variable. But does the localised variable not use the same location as the my variable?

    Andrew
      My previous post wasn't quite accurate. The my $value marks that variable as lexical for the current scope, but a for() loop argument context gets its own store ("scratchpad", see perlguts), as is the case for subroutines. So, although at compilation the my() declaration extends into the sub, the variable inside the sub gets allocated on a different scratchpad, but is also marked as lexical (PADMY):
      use Devel::Peek; my $value = "four"; my @array = ( "one" ); warn "(1):\n" ; Dump($value); foreach $value (@array) { warn "(2):\n" ; Dump($value); print "foreach value: $value\t"; function(); sub function { warn "(3):\n" ; Dump($value); print "function value: $value\n"; } } __END__ (1): SV = PV(0x8b83b00) at 0x8b83768 REFCNT = 1 FLAGS = (PADBUSY,PADMY,POK,pPOK) PV = 0x8b992c8 "four"\0 CUR = 4 LEN = 8 (2): SV = PV(0x8b83c20) at 0x8b82c28 REFCNT = 2 FLAGS = (POK,pPOK) PV = 0x8b962c0 "one"\0 CUR = 3 LEN = 4 (3): SV = NULL(0x0) at 0x8b837b0 REFCNT = 2 FLAGS = (PADBUSY,PADMY) foreach value: one function value:

      As you can see, all addresses of $value are different. The my() just tells the compiler that the symbol $value is to be treated as a lexical variable for the scope in which it was declared, but that doesn't mean it has always the same storage (or only one address location). <update> The $value inside the sub inside the for() loop gets its own $value because the outer $value isn't visible in the scope in which it has been compiled.</update> Bare blocks are different:

      use Devel::Peek; my $value = "four"; warn "(1):\n" ; Dump($value); { $value = "five"; warn "(2):\n" ; Dump($value); } __END__ (1): SV = PV(0x8bcdb00) at 0x8bcd75c REFCNT = 1 FLAGS = (PADBUSY,PADMY,POK,pPOK) PV = 0x8bee7d0 "four"\0 CUR = 4 LEN = 8 (2): SV = PV(0x8bcdb00) at 0x8bcd75c REFCNT = 1 FLAGS = (PADBUSY,PADMY,POK,pPOK) PV = 0x8bee7d0 "five"\0 CUR = 4 LEN = 8
      Welcome to The Monastery, btw ;-)

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