[Melbourne-pm] Postfix conditionals and creating lexicals

Damian Conway damian at conway.org
Thu Jul 12 09:47:58 PDT 2012


Hi all.

The behaviour of a "my...if 0 construct is officially an accident of
implementation. And is at least partially documented as such in the
"perlsyn" manpage (under "Statement Modifiers"):

       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.

Because the construct happens to be implemented in a way that
circumvents the variable's normal garbage collection at the end of its
scope, this technique was widely used in the Bad Old Days to simulate
persistent/static variables:

    sub next_ID {
        my $ID if 0;
        $ID ||= 'AAA00001';
        return ++$ID;
    }

However, as "perlsyn" mentions, this relies on undefined side-effect of
the implementation and is not guaranteed to keep working in future
versions of Perl. Indeed, in Perl 5.10 and later, if you 'use warnings',
you get a compile-time warning about the construct.

Nowadays, there are two safe and reliable ways to achieve the same
effect. Either by promoting the variable to an outer scope and making
the sub a "closure" over it:

    my $ID = 'AAA00001';
    sub next_ID {
        return $ID++;
    }

This works--in any version of Perl 5--because the named subroutine is
referring to the variable, which means the variable's reference-count
is non-zero at the end of its usual scope, so the variable isn't
"recycled" at that point and continues to exist as long as the named
subroutine does.

Alternatively, in 5.10 and later, you can actually declare the variable
as being static within the subroutine, by using 'state' instead of 'my':

    sub next_ID {
        state $ID = 'AAA00001';
        return $ID++;
    }

Either of those is much safer and more future-proof than "my...if 0".

Damian


More information about the Melbourne-pm mailing list