views:

151

answers:

1

I think the answer is yes but I just want to make sure. so if I have

sub something {
    my $_;
    my @array = ...;
    while ( @array ) {
        say;
    }
}

is the my $_; actually effective at lexicalizing the parameter passed to the say?

In this particular case I'm using the DZP::UnusedVarsTests and it's complaining that I haven't used my $_; and I suspect it's a bug since I'm using it in a case where it's implied.

+9  A: 

The short answer is Yes. It makes the functions in that scope use the lexically scoped $_, and not the global $_. If they write back to $_, as in the case of s///, you will have some level of damage control.

Per perldoc perldelta (5.10.0):

"List::Util::first" misbehaves in the presence of a lexical $_ (typically introduced by "my $_" or implicitly by "given"). The variable which gets set for each iteration is the package variable $_, not the lexical $_ [RT #67694].

A similar issue may occur in other modules that provide functions which take a block as their first argument, like

foo { ... $_ ...} list

And, in perldoc perl591delta it goes on to say:

Lexical $_

The default variable $_ can now be lexicalized, by declaring it like any other lexical variable, with a simple

     my $_;

The operations that default on $_ will use the lexically-scoped version of $_ when it exists, instead of the global $_.

In a "map" or a "grep" block, if $_ was previously my'ed, then the $_ inside the block is lexical as well (and scoped to the block).

In a scope where $_ has been lexicalized, you can still have access to the global version of $_ by using $::_, or, more simply, by overriding the lexical declaration with "our $_".

Examples

I wanted to provide some examples of why this functionality would be used:

my $_ = 'BOOM!';

sub something {
    my $_;                         ## Try running with and without
    my @array = qw/foo bar baz/;
    while ( $_ = pop @array ) {
        say;
    }   
}   

something();

say;

And, another example

my $_ = 'foo';

sub something {
  my $_ = $_;  ## Try running with and without
  s/foo/bar/;
  $_;
}

something();

say;
Evan Carroll
`perl591delta`? A-ha! No wonder `my $_` sounded so utterly weird. I'm out of date and out of practice. :(
Charles
Your examples show both HOW this functionality may be used and WHY it should never be used. If you find yourself writing my $_ then you are doing something wrong. If a package requires you to write my $_ then IT is doing something wrong.
Matthew S
@Matthew, if you're writing a package and you don't want bind all of the CORE operations to a named variable, you can localize the `$_` variable. I'm not suggesting this is a good idea, but only because I'm not totally convinced the idea of a default variable is a *good* idea. Certainly, the OO-base type is more appealing from a least-surprise stand point.
Evan Carroll
my personal opinion is that unless there's a technical reason... all these special variables should have been lexical by default anyways.
xenoterracide
`$_` can't be lexical by default. A lexical can't be accessed outside the scope that defined it. (barring passing out a reference or closure)Because of that code like `for (@arr) { print; }` would fail since print should not have access to the lexical `$_`. While it could be argued that perl internal function could cheat and access lexical copies of `$_` it would mean that there would be no way for a custom sub to behave like core functions. Instead of `my $_;` I have usually seen `local $_` which keeps one global `$_` and undoes any local changes when you exit your scope.
Ven'Tatsu
@Ven'Tatsu, `$_` can be lexical yet accessible in a called function if the function uses the `_` prototype. When the function is called, `$_` is aliased to an element of `@_` like any other argument. Try `perl -MData::Dumper -e 'sub foo(_) { print Dumper \@_ }; foo for 1..3;`
daotoad
Ven'Tatsu