Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Re^3: Lexical closures

by backstab (Novice)
on Oct 25, 2008 at 11:08 UTC ( [id://719489]=note: print w/replies, xml ) Need Help??


in reply to Re^2: Lexical closures
in thread Lexical closures

Yes! Thanks. I've never think about aliasing longer than the easy way to work on the elements of an array directly, that is the purpose, in most case, of the foreach loop.

But, I'm continuing playing with that and realize aliasing also implies narrowing the scope of the variable to the loop,

my $i = 123; foreach $i (0..3) { ; } print "$i\n"; # 123

No? If it does not narrow it itself the final value of $i should be 3.

If so, the funny thing is in "foreach my $i" my is not revelant as far we do not control in fact the scope of $i at this point. So, can we consider a bug, or at least an over sanity warn, the fact strict.pm forces us to put it here?

Replies are listed 'Best First'.
Re^4: Lexical closures
by chromatic (Archbishop) on Oct 25, 2008 at 18:40 UTC

    It's not a bug; it was a deliberate design decision in (I believe) 5.004. Besides, you don't have to put my there. The aliasing works with global variables too:

    use 5.010; package Foo; use vars '$i'; use strict; use warnings; sub bar { for $i (1 .. 10) { main::baz( $i ); } } package main; use strict; use warnings; use Test::More tests => 12; $Foo::i = 100; sub baz { my $expect = shift; is( $Foo::i, $expect ); } baz(100); Foo::bar(); baz(100);
      I think we can also show how the aliased variable can be global with the following,
      use vars '$i'; $i = 123; sub foo { my $arg = shift; print "$arg, $i\n"; } foreach $i (0..2) { foo($i); } foo('x'); # obviously alias works only within the loop # Prints, # 0,0 # 1,1 # 2,2 # x,123
      If so, I have a question related to my scope. Within the previous example let's declared $i with my instead.
      my $i; $i = 123; sub foo { my $arg = shift; print "$arg, $i\n"; } foreach $i (0..2) { foo($i); } foo('x'); # Prints, # 0,123 # 1,123 # 2,123 # x,123

      At this point I'm confused in fact. Should not we get the same result? Does not my scope to nested blocks as well?

      It looks like aliasing does not affect my'd variable despite to be within the same scope or nested scope. The previous result is what I have expected using my on the foreach itself.

        In the second snippet, foo() captures $i since $i is a lexical. That means the $i in foo() will always refer to the specific SV associated with $i when foo was compiled. When the loop aliases $i to a different SV, it doesn't affect foo.

        use Devel::Peek; my $i; # Lexical variable sub foo { Dump($i); } Dump($i); # SV ... at 0x226048 \ for $i ( 1 ) { # > same foo(); # SV ... at 0x226048 / Dump($i); # SV ... at 0x226d8c }

        In the first snippet, there is no closure since $i is not a lexical. That means the foo() will always grab the current value of $main::i.

        use Devel::Peek; our $i; # Package variable sub foo { Dump($i); } Dump($i); # SV ... at 0x226d94 for $i ( 1 ) { foo(); # SV ... at 0x226d7c \ same Dump($i); # SV ... at 0x226d7c / }
Re^4: Lexical closures
by GrandFather (Saint) on Oct 25, 2008 at 19:48 UTC

    I invariably write:

    for my $i (0..3) {

    so I am reminded of the scope of the loop variable and am not tempted to think of it having larger scope.

    A very good rule to follow is to always declare lexical variables in the smallest scope possible which precludes declaring declaring loop variables outside the for loop scope


    Perl reduces RSI - it saves typing

      Using my on for/foreach loop variables is not merely making explicit the implicit localization that is provided by the loop: the new lexical variable is distinct from any variable of the same name (lexical or not) in the surrounding scope.

      Note the difference in the following example:

      #!/usr/bin/perl use strict; use warnings; use vars qw($n); $n = "global"; sub foo { my $x = shift; print "$x, $n\n"; } foreach $n (0..2) { foo($n); } print "\$n = $n\n"; foreach my $n (0..2) { foo($n); } print "\$n = $n\n";

      Which produces:

      0, 0 1, 1 2, 2 $n = global 0, global 1, global 2, global $n = global

      After both foreach loops the global $n remains unchanged but within the first (my not used) the global is affected while within the second (my is used) the global is not affected.

      I admit in day-to-day scripts always wanting the foreach element placeholder to be local (in the general sense) to the loop so that having it my'd as far is mandatory as chromatic showed us in the other post.

      But, we can imagine some uses in special cases as debugging, introspection or understanding dead code...

      I did a quick grep on the perl files I have installed for foreach that seems to use a global "$i". I've only found one, maybe, from perl5db.pl.

      It might be an interessing read.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://719489]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (2)
As of 2024-04-25 19:28 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found