Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

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

by ikegami (Patriarch)
on Jul 18, 2006 at 06:05 UTC ( [id://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.

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
Domain Nodelet?
Node Status?
node history
Node Type: note [id://561931]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (4)
As of 2024-04-19 14:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found