DEV Community

Mitch Jackson
Mitch Jackson

Posted on

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

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?

Latest comments (14)

Collapse
 
davorg profile image
Dave Cross • Edited

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.

Collapse
 
mitchjacksontech profile image
Mitch Jackson

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.

Collapse
 
dams profile image
Damien Krotkine

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
Collapse
 
billruppert profile image
Bill Ruppert

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

Collapse
 
kcaran profile image
Keith Carangelo

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

Collapse
 
jrw profile image
jrw

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.

Collapse
 
mitchjacksontech profile image
Mitch Jackson

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.

Collapse
 
jrw profile image
jrw

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.

Collapse
 
maxatome profile image
Maxime SoulΓ©

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;
Collapse
 
mitchjacksontech profile image
Mitch Jackson

Thanks, also good alternatives.

Collapse
 
ribugent profile image
Gerard Ribugent Navarro

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...

Collapse
 
mitchjacksontech profile image
Mitch Jackson

Thanks for this! I will start using this policy.

Collapse
 
thorstenhirsch profile image
Thorsten Hirsch • Edited

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'.

Collapse
 
mitchjacksontech profile image
Mitch Jackson

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.