reason for local($_) ?

Discussion in 'Perl Misc' started by jaialai.technology@gmail.com, Mar 28, 2012.

  1. Guest

    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?
     
    , Mar 28, 2012
    #1
    1. Advertising

  2. >>>>> "jaialai" == jaialai technology <> 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
    <> <URL:http://www.stonehenge.com/merlyn/>
    Smalltalk/Perl/Unix consulting, Technical writing, Comedy, etc. etc.
    See http://methodsandmessages.posterous.com/ for Smalltalk discussion
     
    Randal L. Schwartz, Mar 28, 2012
    #2
    1. Advertising

  3. Tim McDaniel Guest

    In article <70b7b$4f736685$6c1489b1$>,
    <> 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,
     
    Tim McDaniel, Mar 28, 2012
    #3
  4. >>>>> "Ben" == Ben Morrow <> 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
    <> <URL:http://www.stonehenge.com/merlyn/>
    Smalltalk/Perl/Unix consulting, Technical writing, Comedy, etc. etc.
    See http://methodsandmessages.posterous.com/ for Smalltalk discussion
     
    Randal L. Schwartz, Mar 29, 2012
    #4
  5. Tim McDaniel Guest

    In article <>,
    Ben Morrow <> wrote:
    >
    >Quoth Eli the Bearded <*@eli.users.panix.com>:
    >> In comp.lang.perl.misc, Tim McDaniel <> 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,
     
    Tim McDaniel, Mar 29, 2012
    #5
  6. Tim McDaniel Guest

    In article <>,
    Randal L. Schwartz <> wrote:
    >>>>>> "Ben" == Ben Morrow <> 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,
     
    Tim McDaniel, Mar 29, 2012
    #6
  7. On 2012-03-29 16:02, Randal L. Schwartz <> wrote:
    >>>>>> "Ben" == Ben Morrow <> 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.
    | | | |
    __/ | http://www.hjp.at/ | -- Bill Code on
     
    Peter J. Holzer, Mar 29, 2012
    #7
  8. Tim McDaniel Guest

    In article <>,
    Ben Morrow <> wrote:
    >
    >Quoth :
    >>
    >> 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/3393038/does-my-do-anything-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,
     
    Tim McDaniel, Mar 29, 2012
    #8
  9. Guest

    On Mar 28, 2:07 pm, (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."
     
    , Mar 30, 2012
    #9
  10. Guest

    On 3/29/12 4:08 PM, Peter J. Holzer wrote:
    > On 2012-03-29 16:02, Randal L. Schwartz<> wrote:
    >>>>>>> "Ben" == Ben Morrow<> 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.
     
    , Apr 3, 2012
    #10
  11. Tim McDaniel Guest

    This thread was about a project where every sub was started with
    local($_);

    In article <adc97$4f7b61e1$813f0835$>,
    <> wrote:
    >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.


    I'll disagree, because what's also consistent with the evidence is
    "better safe than sorry, prevent an accidental while(<$sth>) or other
    place here stomping $_".

    --
    Tim McDaniel,
     
    Tim McDaniel, Apr 3, 2012
    #11
  12. Ted Zlatanov Guest

    On Tue, 3 Apr 2012 21:41:44 +0000 (UTC) (Tim McDaniel) wrote:

    TM> This thread was about a project where every sub was started with
    TM> local($_);

    TM> In article <adc97$4f7b61e1$813f0835$>,
    TM> <> wrote:
    >> 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.


    TM> I'll disagree, because what's also consistent with the evidence is
    TM> "better safe than sorry, prevent an accidental while(<$sth>) or other
    TM> place here stomping $_".

    My personal approach to $_ is very simple. It follows from two of the
    fundamental laws of programming: Know What The Hell Is Going On; and
    Life's Too Short To Chase Bugs You Could Have Avoided.

    If I know where $_ came from and can *see* the lines of code that
    generated $_, I use $_. So a tight loop or a small block is OK. Never,
    ever would I use $_ inside a function, hoping it's OK. Regardless of
    the optimization, it's just begging a bug report later.

    If I don't know if it may have changed, I switch to using a variable.
    It's very important not to be lazy about this switch. Usually for me it
    happens when the loop or code block exceeds 3 lines or calls a function.

    I thus never have to use "local $_" because I KWTHISGO (hopefully, I say).

    And I choose to avoid relying on $_ because LTSTCBYCHA.

    Hope that helps...
    Ted
     
    Ted Zlatanov, Apr 4, 2012
    #12
  13. (Tim McDaniel) writes:
    > In article <adc97$4f7b61e1$813f0835$>,
    > <> wrote:
    >>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.

    >
    > I'll disagree, because what's also consistent with the evidence is
    > "better safe than sorry, prevent an accidental while(<$sth>) or other
    > place here stomping $_".


    If you don't know what the code at deeper levels in the call tree is
    going to do, how can you be sure that it won't intentionally try to
    change 'the global $_'? It is already a bad idea to add code to work
    around real bugs in other code and fixing these is always
    preferrable (the long-term cost of 'a fucking mess' is usually severly
    underestimated when being compared it with the short term cost of
    'adding another quick & dirty hack, no time to solve the actual
    problem now' ...). It is a really bad idea to add technically useless
    code to work around hypothetical errors in other code.
     
    Rainer Weikusat, Apr 4, 2012
    #13
  14. Tim McDaniel Guest

    In article <>,
    Rainer Weikusat <> wrote:
    > (Tim McDaniel) writes:
    >> In article <adc97$4f7b61e1$813f0835$>,
    >> <> wrote:
    >>>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.

    >>
    >> I'll disagree, because what's also consistent with the evidence is
    >> "better safe than sorry, prevent an accidental while(<$sth>) or other
    >> place here stomping $_".

    >
    >If you don't know what the code at deeper levels in the call tree is
    >going to do, how can you be sure that it won't intentionally try to
    >change 'the global $_'?


    Indeed it could, and thank you for pointing it out. If it is possible
    for a callee to change a value in a caller, one of the two should save
    values and restore them at the end. For example, in the IBM
    System/370 architecture, a subroutine caller must set four registers,
    but the callee is responsible for saving and restoring all other
    registers.

    It's a lot more practical for a callee to protect $_, because it
    happens once at the top of the sub instead of every caller potentially
    having to protect $_ on every call it makes in a $_-using scope.
    I've been assuming that subs preserve $_. Then again, my orkplace
    uses the convention that sub names that start with an underscore are
    supposed to be private and not called outside the source file, but
    I've seen it happen nonetheless.

    I'm thinking that lexical $_ is looking better and better, even with
    the problem with map {} and grep {}.

    --
    Tim McDaniel,
     
    Tim McDaniel, Apr 4, 2012
    #14
  15. On 2012-04-04 14:30, Rainer Weikusat <> wrote:
    > (Tim McDaniel) writes:
    >> In article <adc97$4f7b61e1$813f0835$>,
    >> <> wrote:
    >>>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.

    >>
    >> I'll disagree, because what's also consistent with the evidence is
    >> "better safe than sorry, prevent an accidental while(<$sth>) or other
    >> place here stomping $_".

    >
    > If you don't know what the code at deeper levels in the call tree is
    > going to do, how can you be sure that it won't intentionally try to
    > change 'the global $_'?


    You don't. The local($_) doesn't protect this function from its callees,
    it protects the the callers from this function. It promises to the
    caller that it won't modify $_.

    hp


    --
    _ | Peter J. Holzer | Deprecating human carelessness and
    |_|_) | Sysadmin WSR | ignorance has no successful track record.
    | | | |
    __/ | http://www.hjp.at/ | -- Bill Code on
     
    Peter J. Holzer, Apr 5, 2012
    #15
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. karim
    Replies:
    1
    Views:
    791
    George Ter-Saakov
    Jun 26, 2003
  2. =?Utf-8?B?WVNVVA==?=

    Access local port or Running local exe file

    =?Utf-8?B?WVNVVA==?=, Jan 14, 2006, in forum: ASP .Net
    Replies:
    0
    Views:
    535
    =?Utf-8?B?WVNVVA==?=
    Jan 14, 2006
  3. Jim in Arizona
    Replies:
    8
    Views:
    5,003
    Jim in Arizona
    Jan 24, 2006
  4. lurker
    Replies:
    1
    Views:
    726
    Disco Octopus
    Apr 5, 2005
  5. Chris
    Replies:
    16
    Views:
    576
    Noah Roberts
    Sep 11, 2006
Loading...

Share This Page