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

4

19

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.

Meill answered 3/8, 2010 at 19:28 Comment(4)
I think the answer to your question is mostly covered here in the answer to my question.Wolfe
@Wolfe => The answer there certainly covers some of the aspects of the lexical $_, but not all of them. That's what I would like to cover here.Meill
I know but might as well have a good place to get started ;)Wolfe
Good question. I would +1 but I ran out of votes. :)Cyclo
F
8

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.

Frodin answered 4/8, 2010 at 16:49 Comment(2)
What reasons have been given for for ($foo) {...} rather than local *_ = \$foo;? In my experience the latter is a bit faster (since it doesn't have to setup a scope and an iterator for the single element list), but I would be interested in if there are any safety issues to keep in mind.Meill
Eric, I went looking for the specific reference today and couldn't find it. All I can recall at this point is a warning against local $_ coming from "a person whose opinion I respect" sometime in mid-2009. So, unless I can substantiate the claim better, best ignore it as nothing more than hearsay. The claim was that localization did not cover all edge cases with the admittedly special $_. I never found a bug report or a test case to back up the warning.Frodin
R
3

I once found an issue (bug would be way too strong of a word) that came up when I was playing around with the Inline module. This simple script:

use strict qw(vars subs);
for ('function') {
    $_->();
}
sub function {
  require Inline;
  Inline->bind(C => <<'__CODE__');
void foo() 
{
}
__CODE__
}

fails with a Modification of a read-only value attempted at /usr/lib/perl5/site_perl/5.10/Inline/C.pm line 380. error message. Deep in the internals of the Inline module is a subroutine that wanted to modify $_, leading to the error message above.

Using

for my $_ ('function') { ...

or otherwise declaring my $_ is a viable workaround to this issue.

(The Inline module was patched to fix this particular issue).

Roughspoken answered 4/8, 2010 at 18:44 Comment(0)
P
1

[ Rationale: A short additional answer with a quick summary for perl newcomers that may be passing by. When searching for "perl lexical topic" one can end up here.]

By now (2015) I suppose it is common knowledge that the introduction of lexical topic (my $_ and some related features) led to some difficult to detect at the outset unintended behaviors and so was marked as experimental and then entered into a deprecation stage.


Partial summary of #RT119315: One suggestion was for something like use feature 'lextopic'; to make use of a new lexical topic variable: $^_. Another point made was that an "implicit name for the topicalizing operator ... other than $_" would work best when combined with explicitly lexical functions (e.g. lexical map or lmap). Whether these approaches would somehow make it possible to salvage given/when is not clear. In the afterlife of the experimental and depreciation phases perhaps something may end up living on in the river of CPAN.

Penicillate answered 9/3, 2015 at 15:15 Comment(0)
O
0

Haven't had any problems here, although I tend to follow somewhat of a "Don't ask, don't tell" policy when it comes to Perls magic. I.e. the routines are not usually expected to rely on their peers screwing with non lexical data as a side effect, nor letting them.

I've tested code against various 5.8 and 5.10 versions of perl, while using a 5.6 describing Camel for occasional reference. Haven't had any problems. Most of my stuff was originally done for perl 5.8.8.

Oneway answered 4/8, 2010 at 7:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.