[ABE.pm] stupid perl bugs^Wtricks

Ricardo SIGNES rjbs-perl-abe at lists.manxome.org
Fri Jun 1 06:34:51 PDT 2007


A bug was recently found in perl.  This isn't tremendously exciting, but the
bug itself is cute, and I thought I'd share it with you.

Hopefully you all know about "my" and global variables.  "my" (or "lexical")
variables only exist as long as the block in which they were declared lasts.
(I'm simplifying that, but you get the point.)

Global variables are accessible anywhere, and can be declared, more or less,
with "use vars" or "our" or just by using their fully-qualified name.

"local" is a mechanism for doing "dynamic scoping."  It means that you can say,
"I am replacing this global variable with a localized variable of the same
name, and anything below me in the call stack will see its value, not the
current one."

So, you can do this:

  our $VERSION = 10;
  sub say_version { print "$VERSION\n" }

  sub lie_about_version {
    my $lie = shift;
    local $VERSION = $lie;
    say_version;
  }

  lie_about_version(11);

...and even though the "11" isn't passed in to say_version, it prints 11.  The
value of the global $VERSION has been localized.  If say_version called
something else, THAT would see 11, too.  The original value of 10 would be
restored when lie_about_version's call returned.

If you already knew about local, what you might not have known is that you can
localize not just global variables, but also hash entries on lexical hashes.

What do I mean?  Well:

  my $datum = {
    version => 10,
    flavor  => 'sassafras',
  };

  sub say_version {
    my ($datum) = @_;
    print "$datum->{version}\n";
  }

  sub lie_about_version {
    my ($datum, $lie) = @_;

    local $datum->{version} = $lie;
    say_version($datum);
  }

  lie_about_version($datum, 11);

It does the same thing!  The one entry on the hash is localized, and gets
restored when the localing block returns/ends.  This can be really useful to
subtly tweak data that's being passed around without actually altering it.

Here's the bug:

  my %hash = (foo => 1);
  
  {
    my $key = 'foo';

    local $hash{ $key } = 2;

    $key = 'bar';
  }

  print Dumper(\%hash);

You'd expect it to look just like it did before, right?  But no!

  $VAR1 = {
    'bar' => 1,
    'foo' => 2
  };

The localization remembers that "I localized whatever is in $key on %hash," so
that when it delocalizes, it restores the OLD hash entry value to the NEW value
from $key.  Neat bug!

How important is this bug?  Well, apparently it was introduced in 1998 or so
and nobody noticed until last week.  Probably not very important... just neat!

-- 
rjbs


More information about the ABE-pm mailing list