Interesting Perl Behavior

May 30, 2008 – 2:56 pm

I ran into this problem a while back and wanted to share it. It was a bit unintuitive but documentd so I guess I shouldn’t be surprised by the results. Hopefully this will help someone else avoid this pitfall.

It looks as if declaring a variable with the “my” statement but then guarded with an “if” statement causes the scope of the variable to be global – note that the “use strict ‘vars’;” pragma does not give an error in this case.

#!/usr/bin/perl -w
use strict ‘vars’;

sub foo{
my $val = 0 if (0);
$val = 1 unless defined($val);
print “Val: $val\n”;
$val = 2;
}

foo();
foo();

The output of this call gives:
Val: 1
Val: 2

Although the expected result would seem to be:
Val: 1
Val: 1

Using Google, I found the following nugget from perlsyn:

NOTE: The behaviour of a my statement modified with a statement modifier conditional or loop construct (e.g. my $x if … ) is undefined. The value of the my variable may be undef, any previously assigned value, or possibly anything else. Don’t rely on it. Future versions of perl might do something different from the version of perl you try it out on. Here be dragons.
http://perldoc.perl.org/perlsyn.html#Statement-Modifiers

TwitterFriendFeedDiggStumbleUponYahoo BuzzGoogle ReaderFacebookShare
  • http://www.dieblinkenlights.com Ricardo

    It seems like something like “(my if (0)) $val = 0″ is going on. It’s weird.

  • http://www.shadowcat.co.uk/ Matt S Trout

    That’s a -sort of- bug.

    perl 5.10 actually throws a warning when you trip it, and provides a ‘state $x’ keyword that provides the same functionality as ‘my $x if 0′ safely.

    The basic problem is that the ‘my’ causes a lexical pad entry to be generated at compile time, but because the if 0 prevents the statement running at runtime it doesn’t get reinitialised on your way round the loop.

  • http://brudnopis.blogspot.com Zbigniew Lukasiak

    NOTE: The behaviour of a my statement modified with a statement modifier conditional or loop construct (e.g. my $x if … ) is undefined. The value of the my variable may be undef, any previously assigned value, or possibly anything else. Don’t rely on it. Future versions of perl might do something different from the version of perl you try it out on. Here be dragons.

    from http://perldoc.perl.org/perlsyn.html

    Cheers,
    Z.

  • http://mark.tiefenbruck.org/ Mark Tiefenbruck

    They’re not global. They’re still limited in scope. The value just doesn’t get reset when the same scope is entered more than once. Although known for years, it’s been kept because, instead of reporting it as a bug, people started using this to implement static variables. It certainly wasn’t smart, but that’s what happened, and now we’re stuck with it. Perl 6 will probably fix it.