Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Perl Misc (http://www.velocityreviews.com/forums/f67-perl-misc.html)
-   -   reason for local($_) ? (http://www.velocityreviews.com/forums/t944844-reason-for-local-_.html)

jaialai.technology@gmail.com 03-28-2012 07:29 PM

reason for local($_) ?
 
I recently saw some Perl code at work in which the original author
starts every subroutine with the line local($_);
Every.single.one. Like this:

sub whatever{
local($_);
print "Whatever man!\n";
}

Of course that isn't a real example but my point is
that even in subroutines that don't use $_ this is done.
I have no idea in what context this would ever make sense to do?
Any thoughts?
I suspect that this is some construct from Perl versions < 5. Is it?
If so, what did it mean back then?

Randal L. Schwartz 03-28-2012 08:07 PM

Re: reason for local($_) ?
 
>>>>> "jaialai" == jaialai technology <jaialai.technology@gmail.com> writes:

jaialai> sub whatever{
jaialai> local($_);
jaialai> print "Whatever man!\n";
jaialai> }

jaialai> Of course that isn't a real example but my point is
jaialai> that even in subroutines that don't use $_ this is done.
jaialai> I have no idea in what context this would ever make sense to do?
jaialai> Any thoughts?

Voodoo. It was needed in one place, but he does it everywhere now out
of fear, rather than thinking about it.

It's like all those crazy people who put "i" and "s" modifiers on *all*
regex even if they aren't using any feature affected by it. Silly.

print "Just another Perl hacker,";

--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<merlyn@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/>
Smalltalk/Perl/Unix consulting, Technical writing, Comedy, etc. etc.
See http://methodsandmessages.posterous.com/ for Smalltalk discussion

Tim McDaniel 03-28-2012 08:34 PM

Re: reason for local($_) ?
 
In article <70b7b$4f736685$6c1489b1$29143@news.eurofeeds.com> ,
<jaialai.technology@gmail.com> wrote:
>I recently saw some Perl code at work in which the original author
>starts every subroutine with the line local($_);
>Every.single.one. Like this:
>
>sub whatever{
> local($_);
> print "Whatever man!\n";
>}
>
>Of course that isn't a real example but my point is
>that even in subroutines that don't use $_ this is done.
>I have no idea in what context this would ever make sense to do?


Um, I usually did that. As you know, $_ is a global variable that's
used implicitly by a lot of operations. local()ing it in a sub makes
absolutely sure that anything done in this sub or under it will not
screw up the caller.

I did it in each sub because it was just part of how I started a sub.
It was very quick to type and not likely to cause much overhead.
Otherwise, when editing a sub, I would have had to consider whether
the new code might change $_, and if so go to the top of the sub to
see whether there's a "local $_" already there. And if you only
"local $_" when it's necessary, then there's a chance that you'll
overlook a code path and fail to local() it, causing a bug that may be
subtle.

It's true that 95% of the time I used $_, it was as the implicit
control variable of a foreach loop, which automatically localizes its
control variable. But better an unnecessary local than a silent bug.

"my $_" is relatively newish, coming in in Perl 5.9, it appears.

"man perlsub" has a section on "When to Still Use local".

--
Tim McDaniel, tmcd@panix.com

Randal L. Schwartz 03-29-2012 04:02 PM

Re: reason for local($_) ?
 
>>>>> "Ben" == Ben Morrow <ben@morrow.me.uk> writes:

Ben> That seems bizarre, to me. To *my* mind, $_ belongs to some very small
Ben> block: a for or while (<>) loop a few lines long, or a map or grep
Ben> expression or block. These blocks might occur all over the place, but
Ben> they all set up their own (localised) values for $_, so they don't
Ben> affect each other.

The while *doesn't*. Maybe that's what bit you one day, so that you now
practice this "shake a voodoo stick" thing at it. In which case, you
can borrow my best practice on that and never use $_ for such loops:

while (my $line = <>) {
...
}

print "Just another Perl hacker,"; # the original

--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<merlyn@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/>
Smalltalk/Perl/Unix consulting, Technical writing, Comedy, etc. etc.
See http://methodsandmessages.posterous.com/ for Smalltalk discussion

Tim McDaniel 03-29-2012 04:22 PM

Re: reason for local($_) ?
 
In article <iqjd49-r8h.ln1@anubis.morrow.me.uk>,
Ben Morrow <ben@morrow.me.uk> wrote:
>
>Quoth Eli the Bearded <*@eli.users.panix.com>:
>> In comp.lang.perl.misc, Tim McDaniel <tmcd@panix.com> wrote:
>> > Um, I usually did that. As you know, $_ is a global variable
>> > that's used implicitly by a lot of operations. local()ing it in
>> > a sub makes absolutely sure that anything done in this sub or
>> > under it will not screw up the caller.

>>
>> I find it a much better idea to just use an explicit variable
>> in such cases. In my mind, $_ belongs to the main program, and
>> might even be better off not used there.

>
>That seems bizarre, to me.


To me as well. $_ was designed for repeated use as a temporary and to
be used in a number of string-processing functions. It's so
convenient, whether in a sub or elsewhere, to do

chomp;
s/\r+$//; # not sure this is needed in modern Perl
next if ! s/^\.\.\. //;
if (s/^Root // || s/^AltRoots\d+ //) {
push @roots, $_;
} elsif (my ($depot, $workspace) = s!^View\d+ (//depot/.*) (//.*)$!!) {
...
}

(That's code off the top of my head, a contrived example.) Of course
I could "my" a variable, but then I'd have to drop it in 6 different
places.

>To *my* mind, $_ belongs to some very small block: a for or while
>(<>) loop a few lines long, or a map or grep expression or
>block. These blocks might occur all over the place, but they all set
>up their own (localised) values for $_, so they don't affect each
>other.


Citations:

"man perlsyn" says that a foreach loop always localizes its control
variable,

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 localisation occurs only in a "foreach" loop.

The foreach statement modifier is described well above that, with
"(with $_ aliased to each item in turn)." but no statement at that
point about localization.

The perlfunc docs for map and grep refer to "locally setting $_ to
each element", so I presume that means localizing in the same sense.

Testing shows that they are all indeed localized in the same way:

#! /usr/bin/perl
use strict;
use warnings;
my @names = (' in a loop: wilma', ' barney', ' bambam');
$_ = "\nfred\n";
print;
foreach (@names) { print }
print;
print foreach @names;
print;
map { print } @names;
print;
print grep { 1 } @names;
print;
exit 0;

produces

$ perl local/test/045.pl

fred
in a loop: wilma barney bambam
fred
in a loop: wilma barney bambam
fred
in a loop: wilma barney bambam
fred
in a loop: wilma barney bambam
fred

(That was in Perl 5.8.8, but that's not the sort of thing Perl tends
to change, for fear of breaking code.) (I've never before used
"print" with no arguments, implicitly printing $_. It feels weird.)

But "man perlop" says (in 5.8.8)

Ordinarily you must assign the returned value to a variable, but
there is one situation where an automatic assignment happens. If
and only if the input symbol is the only thing inside the
conditional of a "while" statement (even if disguised as a
"for(;;)" loop), the value is automatically assigned to the global
variable $_, destroying whatever was there previously. (This may
seem like an odd thing to you, but you'll use the construct in
almost every Perl script you write.) The $_ variable is not
implicitly localized. You'll have to put a "local $_;" before the
loop if you want that to happen.

(BTW: "while <>" as a statement modifier works the same way as "while
(<>)" as a loop. I wasn't sure.)

Are there other cases of setting $_ implicitly? I can't think of any.

The while(<>) is an illustration of a silent bug.

And I don't know that "local $_" should be slow, given that every map,
grep, and foreach() has to do it.

>I wouldn't ever use $_ as an ordinary variable, even in the main
>program, except for oneliners with -n or -p.


If nothing else, it's not a descriptive variable name.

--
Tim McDaniel, tmcd@panix.com

Tim McDaniel 03-29-2012 04:31 PM

Re: reason for local($_) ?
 
In article <86vcln8kfq.fsf@red.stonehenge.com>,
Randal L. Schwartz <merlyn@stonehenge.com> wrote:
>>>>>> "Ben" == Ben Morrow <ben@morrow.me.uk> writes:

>
>Ben> That seems bizarre, to me. To *my* mind, $_ belongs to some very small
>Ben> block: a for or while (<>) loop a few lines long, or a map or grep
>Ben> expression or block. These blocks might occur all over the place, but
>Ben> they all set up their own (localised) values for $_, so they don't
>Ben> affect each other.
>
>The while *doesn't*. Maybe that's what bit you one day, so that you
>now practice this "shake a voodoo stick" thing at it. In which case,
>you can borrow my best practice on that and never use $_ for such
>loops:
>
>while (my $line = <>) {
> ...
>}


$ perl -e 'while (my $line = <>) { print $line }'
hello
hello
world
world
about to enter a null line
about to enter a null line


Huh. Right. Newline counts as a character,
Huh. Right. Newline counts as a character,
so the boolean test will not exit the loop when it sees it.
so the boolean test will not exit the loop when it sees it.
It does look cleaner than while (defined(my $line = <>))
It does look cleaner than while (defined(my $line = <>))
^D

But "$line =~" left, right, and center isn't as convenient as implicit $_.

I don't have any mental model of where my() and local() can legally be
placed, so I have to test it:

#! /usr/bin/perl
use strict;
use warnings;
$_ = "fred\n";
while (local $_ = <>) { s/^/ /; print; }
print;
exit 0;

produces (with suitable input):

$ perl local/test/046.pl
hello
hello
world
world
^D
fred

So I guess I'll use
while (local $_ = <>)

Or, I suppose
while (my $_ = <>)
after every place I use Perl upgrades past 5.9.? or whatever it is that
first allowed "my $_".

--
Tim McDaniel, tmcd@panix.com

Peter J. Holzer 03-29-2012 08:08 PM

Re: reason for local($_) ?
 
On 2012-03-29 16:02, Randal L. Schwartz <merlyn@stonehenge.com> wrote:
>>>>>> "Ben" == Ben Morrow <ben@morrow.me.uk> writes:

>Ben> That seems bizarre, to me. To *my* mind, $_ belongs to some very small
>Ben> block: a for or while (<>) loop a few lines long, or a map or grep
>Ben> expression or block. These blocks might occur all over the place, but
>Ben> they all set up their own (localised) values for $_, so they don't
>Ben> affect each other.
>
> The while *doesn't*. Maybe that's what bit you one day, so that you now
> practice this "shake a voodoo stick" thing at it.


Uhm. I don't think jaialai was talking about Ben's code.

hp


--
_ | Peter J. Holzer | Deprecating human carelessness and
|_|_) | Sysadmin WSR | ignorance has no successful track record.
| | | hjp@hjp.at |
__/ | http://www.hjp.at/ | -- Bill Code on asrg@irtf.org

Tim McDaniel 03-29-2012 10:16 PM

Re: reason for local($_) ?
 
In article <ck1f49-plp.ln1@anubis.morrow.me.uk>,
Ben Morrow <ben@morrow.me.uk> wrote:
>
>Quoth tmcd@panix.com:
>>
>> Or, I suppose
>> while (my $_ = <>)
>> after every place I use Perl upgrades past 5.9.? or whatever it is that
>> first allowed "my $_".

>
>Be a little careful with 'my $_'. It currently breaks things like
>List::Util::first that call callbacks with a localised global $_.


Hrm?

first BLOCK LIST

Similar to "grep" in that it evaluates BLOCK setting $_ to
each element of LIST in turn. "first" returns the first
element where the result from BLOCK is a true value. If BLOCK
never returns true or LIST was empty then "undef" is returned.

$foo = first { defined($_) } @list
# first defined value in @list
$foo = first { $_ > $value } @list
# first value in @list which is greater than $value

So if I do them within the scope of "my $_", the $_ in the block I
provide ("$_ > $value" or whatever) will resolve to the lexical, not
to the global?

http://stackoverflow.com/questions/3...-if-is-implied
Evan Carroll (I think) quoted from "perldoc perl591delta" that

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 $_".

After "our $_", note that $_ refers to the same global as was
available outside the lexical "my $_". You can use
local our $_ = EXPR;
to get the package variable with its own localized value.

http://www.effectiveperlprogramming.com/blog/1333 goes farther, to say
that lexical $_ is a bug and given() is unusable. I didn't read it in
any detail to know whether he's saying something useful or incorrect.

--
Tim McDaniel, tmcd@panix.com

jl_post@hotmail.com 03-29-2012 11:21 PM

Re: reason for local($_) ?
 
On Mar 28, 2:07*pm, mer...@stonehenge.com (Randal L. Schwartz) wrote:
>
> Voodoo. *It was needed in one place, but he does it everywhere now out
> of fear, rather than thinking about it.



I know what you mean.

I once saw a Perl script that had "use Win32;" at the top, yet
nothing about the script was Windows-specific. Confused, I asked the
author of the script why he put that in. (I explained to him that
because of that line, the program could only be run on Windows
platforms, even though there was nothing in the script (besides that
line) that required a Windows operating system.)

He replied that he once saw the line "use Win32;" in a Perl script
that worked, so to be safe, he used it in all his Perl scripts.

I explained to him that it didn't need to be there, but of course
that made no difference to him. He just felt safer with it.

To me, that's an example of "Cargo-cult programming": "I don't
know what it does, but a working program had it, so it must be good.
So code that has it must be better than code that doesn't."

jaialai.technology@gmail.com 04-03-2012 08:47 PM

Re: reason for local($_) ?
 
On 3/29/12 4:08 PM, Peter J. Holzer wrote:
> On 2012-03-29 16:02, Randal L. Schwartz<merlyn@stonehenge.com> wrote:
>>>>>>> "Ben" == Ben Morrow<ben@morrow.me.uk> writes:

>> Ben> That seems bizarre, to me. To *my* mind, $_ belongs to some very small
>> Ben> block: a for or while (<>) loop a few lines long, or a map or grep
>> Ben> expression or block. These blocks might occur all over the place, but
>> Ben> they all set up their own (localised) values for $_, so they don't
>> Ben> affect each other.
>>
>> The while *doesn't*. Maybe that's what bit you one day, so that you now
>> practice this "shake a voodoo stick" thing at it.

>
> Uhm. I don't think jaialai was talking about Ben's code.


That is correct. I can affirm that I have never worked with Ben. :)
This was a very enlightening thread an I thank everyone that responded.
At the end of the day Randal is correct, I believe. The author of the
code in question was just blindly adding that line for more or less
uninformed and superstitious reasons.



All times are GMT. The time now is 04:04 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.