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

This seems very strange to me, but it works:

#!/usr/bin/perl use strict; use warnings; my $n1 = 10; our $n2 = 20; sub foo { $n1++; # ??? $n2++; } print "$n1\n"; print "$n2\n"; foo; print "$n1\n"; print "$n2\n";
prints
10 20 11 21

I would expect the $n2 package global to work fine in the above code, and it does. But how does perl allow foo() get away with referring to $n1 like that? When parsing sub foo, shouldn't perl say, "Nope. There's no local here named $n1, and no package global named $n1, so I don't see which $n1 you're talking about."?

BTW, I can see just fine how the following works:

my $bar = 2; { print "Hi \$bar ($bar), good to see you.\n"; }
because that's just how scoping works. But it looks to me like there's supposed to be a distinction between that and the way foo() above is doing business... (confused)

Replies are listed 'Best First'.
Re: Using an "outer" lexical in a sub?
by Joost (Canon) on Nov 01, 2006 at 20:22 UTC
    Perl doesn't really make a distinction between "normal" blocks and subroutine blocks with regard to lexical scoping rules. You can even take and copy a reference to a subroutine that accesses lexicals in its outer scope that way. This is by design. See also perlfaq7 (what's a closure?), perlsub and perlref.

    use strict; sub make_ref { my $name = shift; my $i = 99; return sub { print "ref $name: ",$i++,"\n"; } } my $ref1 = make_ref("sub1"); my $ref2 = make_ref("sub2"); for (1 .. 10) { $ref1->(); $ref2->() if $_ % 2 == 0; }
    output:
    ref sub1: 99 ref sub1: 100 ref sub2: 99 ref sub1: 101 ref sub1: 102 ref sub2: 100 ref sub1: 103 ref sub1: 104 ref sub2: 101 ref sub1: 105 ref sub1: 106 ref sub2: 102 ref sub1: 107 ref sub1: 108 ref sub2: 103

      Very interesting... each copy of that referenced subroutine which gets returned by make_ref() gets its own "freeze-dried" copy of $i...

      I've got some reading to do. Thank you, and thanks also for the link to perlfaq7.

      Hm... I just tried something which, to me, looks like it should behave the same as the above code, but it won't do the same trick:
      #!/usr/bin/perl use strict; use warnings; my $ref1; my $ref2; { my $n = 10; $ref1 = sub { print( $n++, "\n" ) }; $ref2 = sub { print( $n++, "\n" ) }; } $ref1->(); # --> 10 $ref1->(); # --> 11 $ref1->(); # --> 12 print "\n"; $ref2->(); # --> 13 Huh? $ref2->(); # --> 14 ? $ref2->(); # --> 15 ?

      I'd expect that first call to $ref2->(); to start up with its own squirreled-away $n (starting at 10). Why doesn't it?

        It doesn't start with it's own version of $n, because at the time you're creating $ref1 and $ref2 $n is the same variable.

        You can look at it like this:

        sub test() { my $n = 10; { print( $n++, "\n" ) } { print( $n++, "\n" ) } print "\$n is now $n\n; }
        Now, you can see that both blocks access the same variable (i.e. $n will be 12 at the end of test()).

        If you run test() again, my $n = 10; will effectively be a new variable $n but if you still have a subref somewhere that accesses the old $n (i.e. a reference to a to one or more of the inner blocks) that code ref will hang on to its variables and new ones will be created if necessary.

        Note that in my earlier post the outer subroutine is called twice and that will create the new lexical variable.

        { my $n = 10; $ref1 = sub { print( $n++, "\n" ) }; $ref2 = sub { print( $n++, "\n" ) }; }
        When the anonymous subroutine that is stored in $ref1 is created it increases the reference count for that instance of $n to 2.

        When the anonymous subroutine that is stored in $ref2 is created it increases the reference count for that instance of $n to 3.

        The two anonymous subroutines share the same $n in this case.

Re: Using an "outer" lexical in a sub?
by ikegami (Patriarch) on Nov 01, 2006 at 20:16 UTC

    As you discovered, lexical vars can be globals too :)

    Now try the following snippets:

    #!/usr/bin/perl #use strict; use warnings; sub foo { $n++; } $n = 10; print "$n\n"; # 10 foo(); print "$n\n"; # 11
    #!/usr/bin/perl use strict; use warnings; sub foo { $n++; } # Compile-time (strict) error! our $n = 10; print "$n\n"; # 10 foo(); print "$n\n"; # 11
    #!/usr/bin/perl use strict; use warnings; # "our $n;" disables "use strict 'vars';" for $n for the # remainder of the lexical scope in which it is located. sub foo { our $n; $n++; } our $n = 10; print "$n\n"; # 10 foo(); print "$n\n"; # 11
    #!/usr/bin/perl use strict; use warnings; sub foo { my $n; $n++; } # Different $n! my $n = 10; print "$n\n"; # 10 foo(); print "$n\n"; # 10
    #!/usr/bin/perl use strict; use warnings; sub foo { $n++; } # Compile-time (strict) error! my $n = 10; print "$n\n"; foo(); print "$n\n";
    #!/usr/bin/perl use strict; use warnings; my $n = 10; sub foo { $n++; } print "$n\n"; # 10 foo(); print "$n\n"; # 11
      #!/usr/bin/perl use strict; use warnings; # "our $n;" disables "use strict 'vars';" for $n for the # remainder of the lexical scope in which it is located. sub foo { our $n; $n++; } our $n = 10; print "$n\n"; # 10 foo(); print "$n\n"; # 11

      Well, this example helps me somewhat (though seemingly (to me) not directly with what I was originally confused about). Thank you. I'd previously always written "our $n = $whatever;" assuming that it atomically meant, "create a package global named $n with $whatever value". Looking more closely at our though, I see that that statement is really doing *2* separate things:

      1. Letting me refer to $main::n as just plain $n.
      2. Setting $n to something ($n springs into existence at *this* point).

      (Should've read the docs on our more carefully -- they're very good.)

      So, in your example above, I now see that "our $n;" in sub foo isn't defining anything -- just telling perl that I'll be referring to $main::n in here as "$n". :)

        Pragmas (such as use strict), my variables, our declerations (but not package variables), package statements, etc all have lexical scope. A lexical scope spans (includes) its child lexical scope.
        use strict; sub f { # strict still in effect in this child block if (...) { # strict still in effect in this child block for (...) { # strict still in effect in this child block { # strict still in effect in this child block } } } }
        my $n; sub f { # $n is still accessible in this child block if (...) { # $n is still accessible in this child block for (...) { # $n is still accessible in this child block { # $n is still accessible in this child block } } } }
        { use strict; # strict still in effect } # strict no longer in effect
        { my $n; # $n accessible. } # $n no longer accessible.
Re: Using an "outer" lexical in a sub?
by GrandFather (Saint) on Nov 01, 2006 at 20:14 UTC

    $n1 is simply a global. It is global to everything (including subroutines and nested blocks) from the point where it is declared onward.

    Actually no language I can think of (of the small number I've used) hides global variables from subroutines/functions/class members. Is there a bigger picture here that is leading to your confusion?

    Update: Fletch is quite right that I'm playing fast and loose with nomenclature here. C's 'file scope' is the notion I intended by "global". My appologies for any confusion caused.


    DWIM is Perl's answer to Gödel

      It's a lexical at the outermost scope (what'd probably be referred to as "file scope" in C-land) and it's visibility is limited to everything lexically within the file it's declared in (after the point at which the declaration occurs, of course).

      I think you're getting --'d here because calling a file scope'd lexical a "global", the term usually in Perl usage referring to package variables which live in the truly global symbol table, is only likely to further confuzzle people.

      Update: Someone else below has them called "file statics" in C; I've heard both terms I think.

Re: Using an "outer" lexical in a sub?
by cmeyer (Pilgrim) on Nov 01, 2006 at 20:04 UTC

    You are learning about closures. :)

    Have a good read at perlsub, and pay close attention to all the talk about lexical scoping.

    -Colin.

    WHITEPAGES.COM | INC

Re: Using an "outer" lexical in a sub?
by derby (Abbot) on Nov 01, 2006 at 20:36 UTC

    From perlsub:

    If declared at the outermost scope (the file scope), then lexicals work somewhat like C’s file statics. They are available to all func‐ tions in that same file declared below them, but are inaccessible from outside that file. This strategy is sometimes used in modules to create private variables that the whole module can see.

    So

    my $var; sub foo { $var++; }
    is similar (from a scope perspective) to:
    sub foo { my $var; { $var++; } }

    Trying to avoid this *unintended* global issue is why you see some perl code with subroutines called main or with all the subs defined at the beginning of a file and the driver portion at the end:

    sub foo { ... } sub bar { ... } my $var = 0; foo(); bar();
    or
    main(); sub main { my $var = 0; foo(); bar(); } sub foo { ... } sub bar { ... }
    I neither condemn nor condone these approaches - just pointing out why some devs do what they do; although the reverse definition always seemed too pascally to me.

    -derby
Re: Using an "outer" lexical in a sub?
by imp (Priest) on Nov 01, 2006 at 20:41 UTC
    The lexical variable in your example is in the package scope.

    Compare this:

    package foo; our $n = 1; package main; print "n = ", $foo::n , $/; # n = 1
    With this:
    package foo; my $n = 1; package main; print "n = ", $foo::n , $/; # nothing

    A related topic is the behaviour of closures, which was mentioned by several other monks above. One of the less obvious behaviours of closures can be seen in the following example:

    sub foo { my $n = 1; print $n; bar(); print $n; bar(); sub bar { $n++; } } foo(); foo(); #output 1211
    The inner sub 'bar' keeps a reference to the instance of '$n' that existed during the first call to 'foo'. People frequently run into this problem when they first start using mod_perl with Apache::Registry, as documented here:
    mod_perl / Apache::Registry accidental closures
Re: Using an "outer" lexical in a sub?
by holcapek (Sexton) on Nov 02, 2006 at 08:40 UTC
    There is something called package scope. In each point in time, perl code is in exactly one package scope.

    There is something pretty different called lexical scope. In each point of time, perl code can be in one or more lexical scopes. Lexical scopes are distributed into nested lexical scopes.

    my $outer = 1; # lexical file scope { my $inner = 1; # here I can see both $inner and $outer # as $outer is "inherited" from the outer # lexical scope { my $inner = 2; # this $inner is completely different $inner # than the $inner in the direct outer scope # but still I can see $outer } # now I can see $inner that is equal to 1 } # now I can see only $outer
    For additional reading, I recommend perlsub, namely "Private Variables via my()".