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

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

sub abc() { $_ = 'x'; } sub xyz() { foreach(4..5) { print " Before:$_\n"; print " After:$_\n"; } } foreach(1..2) { print "Before:$_\n"; xyz(); print "Mid:$_\n"; abc(); print "After:$_\n"; }

The above code produces

Before:1 Before:4 After:4 Before:5 After:5 Mid:1 After:x Before:2 Before:4 After:4 Before:5 After:5 Mid:2 After:x

I have a simple loop which contains a call that assigns a value to $_. The sub actually does this with

while (<IN>){}

This would indicate that $_ should be viewed as a global variable as used in abc(). However, in the xyz() sub $_ appears to be non-global as it leaves the $_ in the caller alone. What is the scope of $_ supposed to be?

Replies are listed 'Best First'.
Re: What is the scope of $_?
by Athanasius (Archbishop) on Nov 26, 2012 at 14:55 UTC

    $_ is global in scope (see perlvar#General-Variables). However, in

    sub xyz() { foreach(4..5) { ...

    $_ is implicitly localised, as though written:

    sub xyz() { foreach local $_ (4..5) { ...

    which explains the behaviour you’re seeing.

    Update: From perlsyn#Foreach-Loops:

    If the variable is preceded with the keyword my, then it is lexically scoped, and is therefore visible only within the loop. 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. This implicit localization occurs only in a foreach loop.

    Hope that helps,

    Athanasius <°(((><contra mundum

Re: What is the scope of $_?
by moritz (Cardinal) on Nov 26, 2012 at 16:10 UTC

      Interesting? More like buggy :-) Let's hope this gets fixed and given starts to become a bit more safe :-)

Re: What is the scope of $_?
by tobyink (Canon) on Nov 26, 2012 at 16:26 UTC

    There is more than one $_. All your examples use the global $_. This is global in scope (as are all the "punctuation variables", except @_ which is just weird).

    However, certain constructs implicitly localize variables. for loops do this.

    Also (from Perl 5.10) you can create a new variable called $_ using my $_ or given (though the behaviour of given will change in 5.18 - it will not implicitly create a lexical $_). These have the same scope as any other lexical variables - the remainder of the block they're defined in, where the file itself counts as a block.

    If you want to access your caller's lexical $_, then the official way is to use a sub prototype. I've also written lexical::underscore which allows you to delve multiple levels down the call stack.

    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
      <tangent> How is @_ not global in scope? I mean, it gets implicitly localized on any subroutine call, but it's present by default and package independent:
      use strict; use warnings; @_ = @ARGV; package Foo; print for @_; @_ = qw(1 2 3 4 5); { local @_ = reverse @_; print for @_; } package main; print for @_;
      </tangent>

      #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

        You are correct. I was under the impression that a reference to @_ behaved differently than a reference to another localized array, once the localization went out of scope.

        But the following example appears to show they behave the same...

        use strict; use Data::Dumper; our @X; my ($underscore, $scissors); @_ = (1..3); @X = (1..3); sub foo { local @X = (4..6); $underscore = \@_; $scissors = \@X; } foo(4..6); print Dumper($underscore, $scissors);

        So (like $_) @_ is just a global array that gets localized by certain control structures. (In particular, sub.)

        perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'

      If all the OP's examples use the global $_ then printing it at the end would show the last value assigned. What actually happens is a warning for 'Use of uninitialized value $_ ...' The subroutine uses whatever $_ that is in scope when it is called.

      use warnings; use strict; sub abc() { $_ = 'x'; } foreach(1..2) { my $loopvar = 'in the loop'; print "Before:$_\n"; abc(); print "After:$_\n"; } print "\$_ = $_\n"; # warning for uninitialized value $_ (global scop +e) abc(); print "\$_ = $_\n"; # prints $_ = x

        As I said, all the OP's examples use the global $_ but some Perl control structures localize that variable.

        The same effect is illustrated here using global $::x...

        use warnings; use strict; sub abc() { $::x = 'x'; } foreach $::x (1..2) { print "Before:$::x\n"; abc(); print "After:$::x\n"; } print "\$::x = $::x\n"; # warning for uninitialized value $x (global +scope) abc(); print "\$::x = $::x\n"; # prints $x = x
        perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
Re: What is the scope of $_?
by Anonymous Monk on Nov 26, 2012 at 15:09 UTC
Re: What is the scope of $_?
by Anonymous Monk on Nov 26, 2012 at 21:40 UTC
    Dunno ... that's why I don't use it. All of these statements allow you to define your own my variable which will capture the necessary cursor-position within the body of the loop, thereby eliding the problem completely. There must be a reason for that...