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;
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;
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?
Top comments (14)
Other alternatives:
Thanks, also good alternatives.
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: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.
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.
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.
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...
Thanks for this! I will start using this policy.
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'.
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.
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.
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.
I am quite surprised. A quick scan found an instance of this syntax in my production code.
After reading your post I thought, "maybe I should check...", and sure enough I found multiple instances. Thanks!