http://www.perlmonks.org?node_id=1014504


in reply to foreach-loop-local var in sub

... strange, in your case I would expect to see a warning like "variables won't stay shared"...

These kind of problems are easily avoided by either using lexical subs:

use strict; use warnings; foreach (0, 1) { my $i = $_; my $print = sub { print $i; }; $print->(); # 0,1 }

or just not expecting to be able to easily redefine package subs at runtime, they are defined only once at compile time:

use strict; use warnings; my $i; sub my_print { print $i; }; foreach (0, 1) { $i = $_; my_print(); # 0,1 }

Anyway, while there are good use-cases for closures, I'd expect a beginner to go easy and pass arguments normally :

use strict; use warnings; sub my_print { my ($i)=@_; print $i; }; foreach (0, 1) { my_print($_); # 0,1 }

Cheers Rolf

Replies are listed 'Best First'.
Re^2: foreach-loop-local var in sub
by NetWallah (Canon) on Jan 22, 2013 at 02:39 UTC
    I get strange results from a slight variation:
    use strict; use warnings; my $i = 6; sub my_print { print $i; }; for ($i = 1; $i < 3; $i++) { my_print(); print " (C-Style:\$i==$i)\n"; } for $i (qw|x y|) { my_print(); print " (Perl Style:\$i==$i)\n"; }
    Output:
    1 (C-Style:$i==1) 2 (C-Style:$i==2) 3 (Perl Style:$i==x) 3 (Perl Style:$i==y)
    Not that I would write code like this, but how come the "perl style" does not update the "$i" the sub sees ?

                 Most people believe that if it ain't broke, don't fix it.
            Engineers believe that if it ain't broke, it doesn't have enough features yet.

      From perlsyn#Foreach Loops

             Otherwise, the variable is
             implicitly local to the loop and regains its former value upon exiting
             the loop.  If the variable was previously declared with "my", it uses
             that variable instead of the global one, but it’s still localized to
             the loop. 
      

      If you also check the references you will see that the '$i' are pointing to different locations.

      use strict; use warnings; $,=","; $\="\n"; my $i = 6; sub my_print { print $i,\$i; } ; for $i (qw|x y|) { my_print(); print " (Perl Style:\$i==$i)",\$i,"\n"; }
      OUTPUT
      6, SCALAR(0x8fa4e38) (Perl Style:$i==x), SCALAR(0x8f86760), 6, SCALAR(0x8fa4e38) (Perl Style:$i==y), SCALAR(0x8fa4da8),

      That's why PBP says to always use lexical loop vars in foreach!

      Cheers Rolf

        Well, Foreach Loops’s use of the word “local” is somewhat misleading, as it suggests dynamic scoping (via the local keyword), whereas the scoping here is lexical. The Camel Book (4th Edition, page 143, underlining added) is a little clearer:

        The loop variable is valid only from within the dynamic or lexical scope of the loop and will be implicitly lexical if the variable was previously declared with my. This renders it invisible to any function defined outside the lexical scope of the variable, even if called from within that loop. However, if no lexical declaration is in scope, the loop variable will be a localized (dynamically scoped) global variable; this allows functions called from within the loop to access that variable. In either case, any previous value the localized variable had before the loop will be restored automatically upon loop exit.

        The dynamic scoping of a global variable can be easily seen by changing my $i = 6; to our $i = 6; in NetWallah’s example.

        Hope that helps,

        Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,