Perl 5.30 deprecates use of my() in a false conditional
Mitch Jackson

Mitch Jackson @mjac

About: all of your thoughts are in a simulation

Location:
Atlanta, GA
Joined:
Mar 29, 2018

Perl 5.30 deprecates use of my() in a false conditional

Publish Date: Jun 10 '19
19 14

Perl 5.30.0 is released (changelog). With it comes a breaking change for me. It has been a long time since I've faced a breaking change with perl.

Deprecated use of my() in false conditional.

I have been using this deprecated syntax liberally like so:

# This syntax generates a fatal error in perl 5.30
#
# Initialize $foo
#   If $bar tests true, $foo = 'foobar'
#   If $bar tests false, $foo = undef
my $foo = 'foobar' if $bar;
Enter fullscreen mode Exit fullscreen mode

There has been a long-standing bug in Perl that causes a lexical variable not to be cleared at scope exit when its declaration includes a false conditional.

This could make for interesting bugs. The scoped variable declared this way may unexpectedly persist data!

# Use this instead
my $foo;
if ( $bar ) {
  $foo = 'foobar';
}

# Or this
my $foo;
$foo = 'foobar' if $bar;
Enter fullscreen mode Exit fullscreen mode

According to RT# 133543, the deprecation will not always be triggered with this syntax! Therefore, I feel I can't trust a run of a test suite under 5.30 to identify all the offending code statements.

Is anybody else surprised to learn this declaration pattern is problematic?

Comments 14 total

  • Thorsten Hirsch
    Thorsten HirschJun 10, 2019

    Uhm... no. I can't believe a lot of people used this pattern - why would you want a conditional declaration? You can't even call 'if($foo)' when using strict. I've always written code like '# Or this'.

    • Mitch Jackson
      Mitch JacksonJun 10, 2019

      I'm not convinced a lot of people use this pattern. I picked it up so long ago, I can't tell you where I learned it. I've preferred it for it's brevity.

  • Gerard Ribugent Navarro
    Gerard Ribugent NavarroJun 17, 2019

    I saw this pattern on old code at the company I work. Fortunately, there is a perl critic policy to detect this mistakes.

    metacpan.org/pod/Perl::Critic::Pol...

    • Mitch Jackson
      Mitch JacksonJun 17, 2019

      Thanks for this! I will start using this policy.

  • Maxime Soulé
    Maxime SouléJun 17, 2019

    Other alternatives:

    # same length, but if $bar is false, $foo equals $bar, so not necessarily undef:
    my $foo = $bar && 'foobar';
    
    # otherwise, less perlish and longer:
    my $foo = $bar ? 'foobar' : undef;
    
  • jrw
    jrwJun 17, 2019

    I was surprised when I first learned of this. I'm not sure why they didn't just fix the bug, so that

    my $foo = "foobar" if $bar;

    would be equivalent to

    my $foo;
    $foo = "foobar" if $bar;

    Or, I'm not sure why they didn't fatalize the syntax, regardless of the value of $bar. Today $bar == 1 and your code works; tomorrow $bar == 0 and you get a fatal error?

    I'm sure there's lots of code out there using the deprecated syntax.

    • Mitch Jackson
      Mitch JacksonJun 17, 2019

      This syntax had a bug. The variable did not get garbage collected when it fell out of scope. Perhaps the decision to fatalize it was a practical decision to fix that bug.

      • jrw
        jrwJun 17, 2019

        Probably it was too hard to just fix it, so fatalizing it was the next best thing? But it seems very risky/buggy to fatalize only in the cases where the conditional expression is false, since that expression is not a constant.

  • Bill Ruppert
    Bill RuppertJun 17, 2019

    I am quite surprised. A quick scan found an instance of this syntax in my production code.

    • Keith Carangelo
      Keith CarangeloJul 3, 2019

      After reading your post I thought, "maybe I should check...", and sure enough I found multiple instances. Thanks!

  • Damien Krotkine
    Damien KrotkineJun 18, 2019

    To people wondering why this syntax persisted so long: the bug produced by this syntax was actually the only way to have state variables, before the keyword state was introduced. This is why the bug was not fixed. Some people actually used it as a short syntax to implement a state variable:

    $ perl -E 'sub flip_flop { my $t if 0; $t = !$t; say $t ? "flip" : "flop"} flip_flop() for 1..4'
    flip
    flop
    flip
    flop
    
  • Dave Cross
    Dave CrossJul 14, 2019

    This syntax has been generating deprecation warnings since Perl 5.10 in 2007 (see metacpan.org/pod/release/XSAWYERX/...). And it's been telling you that it would become fatal in 5.30 since the release of 5.26 in 2017.

    Surely that's enough time to fix this "bug" in your code? :-)

    And, to be clear, this is not deprecation. This is fatalising a deprecation warning.

    • Mitch Jackson
      Mitch JacksonJul 15, 2019

      Dave, I've never seen a deprecation warning. If I had, of course this fatalising would not have been surprising. Probably because I was not using the syntax to hack a persistent state variable.

      I found this puzzling, until reading comment history on RT#133543. It's mentioned the deprecation warning may not be displayed for some instances of the syntax.

Add comment