Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Re: Rethrowing with die $@ considered harmful (local $_ buggy)

by ikegami (Pope)
on Jul 18, 2006 at 06:05 UTC ( #561931=note: print w/ replies, xml ) Need Help??


in reply to Rethrowing with die $@ considered harmful

Similarly, I've started noticing issues with the common practice of doing local $_. In some situations, that's not enough to prevent damage to the caller. Using local *_ fixes those problems. For example, consider the following function:

sub dequote { local $_ = @_ ? $_[0] : $_; s/^"//; s/"$//; s/\\(.)/$1/g; return $_; }

It assigns its parameter (or $_ if there are no parameters) to $_. It attempts to prevent damage to the caller by localizing $_ first, but I will show it doesn't always work.

Case 1

$_ is tied, or $_ is an alias to something which is tied.

Running
use strict; use warnings; sub dequote { local $_ = @_ ? $_[0] : $_; s/^"//; s/"$//; s/\\(.)/$1/g; return $_; } { package MyTie; sub TIESCALAR { bless(\my $var, shift) } sub FETCH { my $self = shift; print("FETCH\n"); return $$self; } sub STORE { my $self = shift; $$self = shift; print("STORE $$self\n"); return $$self;} } tie my $var, 'MyTie'; $var = '"John \"Foo\" Bar"'; print dequote, "\n" foreach $var;

gives

STORE "John \"Foo\" Bar" FETCH STORE FETCH Use of uninitialized value in concatenation (.) or string at 561931.pl + line 18. STORE FETCH Use of uninitialized value in substitution (s///) at 561931.pl line 6. FETCH Use of uninitialized value in substitution (s///) at 561931.pl line 7. FETCH Use of uninitialized value in substitution (s///) at 561931.pl line 8. FETCH STORE Use of uninitialized value in print at 561931.pl line 25.

Case 2

pos($_) is used by the caller.

Running
use strict; use warnings; sub dequote { local $_ = @_ ? $_[0] : $_; s/^"//; s/"$//; s/\\(.)/$1/g; return $_; } $_ = 'abcd'; /\G .. /gcx; print(pos(), "\n"); dequote('"John \"Foo\" Bar"'); print(pos(), "\n");

gives

2 Use of uninitialized value in print at 561931.pl line 18.

Changing
   local $_ = @_ ? $_[0] : $_;
to
   my $s = @_ ? $_[0] : $_;
   local *_ = \$s;
gives

2 2

The Solution

sub dequote { #local $_ = @_ ? $_[0] : $_; # XXX my $s = @_ ? $_[0] : $_; # Fix local *_ = \$s; # Fix s/^"//; s/"$//; s/\\(.)/$1/g; return $_; }

After making that change, the programs output
STORE "John \"Foo\" Bar" FETCH John "Foo" Bar

and

2 2

respectively.


Comment on Re: Rethrowing with die $@ considered harmful (local $_ buggy)
Select or Download Code
Replies are listed 'Best First'.
Re^2: Rethrowing with die $@ considered harmful
by Ieronim (Friar) on Jul 18, 2006 at 07:48 UTC
    In my own code i always local'ize $_ using for, as recommended in Camel III:

    Solution 2

    sub dequote { my $string = @_ ? $_[0] : $_; for ($string) { s/^"//; s/"$//; s/\\(.)/$1/g; return $_; } }
    It's IMO even more readable than the local $_ variant, and passes all your tests.

         s;;Just-me-not-h-Ni-m-P-Ni-lm-I-ar-O-Ni;;tr?IerONim-?HAcker ?d;print
Re^2: Rethrowing with die $@ considered harmful
by xmath (Hermit) on Jul 22, 2006 at 10:44 UTC
    Another alternative: The local of Data::Alias does it right (it ignores ties and such), so this works:
    alias(local $_) = @_ ? $_[0] : $_;

    And it avoids localizing the entire *_

    The parens here are needed because alias local $_ = ... would be parsed as alias(local $_ = ...) which means the assignment would make an alias, which isn't what you want here.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://561931]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (12)
As of 2015-07-31 11:29 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (276 votes), past polls