http://qs1969.pair.com?node_id=61147

modred has asked for the wisdom of the Perl Monks concerning the following question:

The following psuedo-code illustrates something I have just recently run into when relying on $_.

while(<FILE>) { if(/matches/) # use of $_, everything is ok { $object->doSomething($part_of_line); } print "$_\n"; # here $_ has a value of undef and causes problems }

and from the object module

sub doSomething { ... open(FILE2, $file2); while(<FILE2>) { # do more stuff } # At this point in the code, $_ is undef and since $_ is # global... }

This is fixed by adding a local($_); to the doSomething subroutine, is it (adding a local($_);) something that I should be doing on a regular basis in the subroutines of my modules or did I just happen upon an out of the ordinary situation?

Replies are listed 'Best First'.
Re: localization of $_
by japhy (Canon) on Feb 28, 2001 at 00:07 UTC
    Module code should localize any special variables it uses in each location it uses them. This is a smart and sane practice. Watch:
    package MyConfigReader; sub readConfig { my ($file,$var) = @_; open FILE, "< $file" or die "can't read $file: $!"; while (<FILE>) { chomp; my ($k,$v) = split /=/, $_, 2; return $v if $k eq $var; } close FILE; return; }
    That looks innocent, right? Watch it get blown to hell:
    use MyConfigReader; $/ = "not gonna happen"; MyConfigReader::readConfig("whatever.dat");
    My program has just modified the input record separator variable. The module relied on that being \n, and now it isn't.
    sub readConfig { my ($file,$var) = @_; local ($_, $/); $/ = "\n"; # rest of function }
    So yes, this is something you should be doing. Trusting the user is potentially silly. Perhaps there should be a switch like -T that catches blind use of "true globals" like you demonstrated.

    japhy -- Perl and Regex Hacker
Re: localization of $_
by TheoPetersen (Priest) on Feb 28, 2001 at 00:03 UTC
    It's a common enough situation. I think a lot of us figured it out in just this way too.

    perlman:perlsub, perlman:perlsyn and perlman:perlvar all have some comments about this, but it can be hard to get the picture from those without someone (or some bug) pointing it out. perlman:perlvar states that $_ is assigned to in your while case, but doesn't make it clear that $_ isn't localized by while as a foreach would.

    Either localize $_ yourself, or switch to another while style for any loop that calls subroutines: while (my $line = <FILE>) {

Re: localization of $_
by mr.nick (Chaplain) on Feb 28, 2001 at 00:23 UTC
    If you use $_ often as a temporary variable, you should definately use local $_; at the beginning of your subroutines to prevent this exact situation from happening.

      ...and you can also be defensive and protect yourself from other code that isn't as nice:

      sub mine { local( $_ ); while( <FILE> ) { s/this/that/g; { local( $_ )= $_; yours( $_ ); } s/that/this/g; }
      though if you find yourself doing that I strongly suggest you just switch to using my $var instead of $_.

              - tye (but my friends call me "Tye")