perlgloballexicalperl5.10

The good, the bad, and the ugly of lexical $_ in Perl 5.10+


Starting in Perl 5.10, it is now possible to lexically scope the context variable $_, either explicitly as my $_; or in a given / when construct.

Has anyone found good uses of the lexical $_? Does it make any constructs simpler / safer / faster?

What about situations that it makes more complicated? Has the lexical $_ introduced any bugs into your code? (since control structures that write to $_ will use the lexical version if it is in scope, this can change the behavior of the code if it contains any subroutine calls (due to loss of dynamic scope))

In the end, I'd like to construct a list that clarifies when to use $_ as a lexical, as a global, or when it doesn't matter at all.


NB: as of perl5-5.24 these experimental features are no longer part of perl.


Solution

  • IMO, one great thing to come out of lexical $_ is the new _ prototype symbol.

    This allows you to specify a subroutine so that it will take one scalar or if none is provided it will grab $_.

    So instead of writing:

    sub foo {
        my $arg = @_ ? shift : $_;
    
        # Do stuff with $_
    }
    

    I can write:

    sub foo(_) {
        my $arg = shift;
    
        # Do stuff with $_ or first arg.
    }
    

    Not a big change, but it's just that much simpler when I want that behavior. Boilerplate removal is a good thing.

    Of course, this has the knock on effect of changing the prototypes of several builtins (eg chr), which may break some code.

    Overall, I welcome lexical $_. It gives me a tool I can use to limit accidental data munging and bizarre interactions between functions. If I decide to use $_ in the body of a function, by lexicalizing it, I can be sure that whatever code I call, $_ won't be modified in calling code.

    Dynamic scope is interesting, but for the most part I want lexical scoping. Add to this the complications around $_. I've heard dire warnings about the inadvisability of simply doing local $_;--that it is best to use for ( $foo ) { } instead. Lexicalized $_ gives me what I want 99 times out of 100 when I have localized $_ by whatever means. Lexical $_ makes a great convenience and readability feature more robust.

    The bulk of my work has had to work with perl 5.8, so I haven't had the joy of playing with lexical $_ in larger projects. However, it feels like this will go a long way to make the use of $_ safer, which is a good thing.