perlsyn
, "Statement-Modifiers" section clearly states that
The behaviour of a
my
,state
, orour
modified with a statement modifier conditional or loop construct (for example,my $x if ...
) is undefined.
Unfortunately this list is missing local
and its own documentation doesn't cover its behavior either. I assume it is undefined as well and docs are just incomplete in those particular sections.
Is this actually covered in docs anywhere?
The undefined behavior of using a statement modifier on my
& Co., such as
my $x = 1 if $flag; # UNDEFINED behavior
is due to the fact that the my $x
declaration happens at compile time while the = 1
assignment happens at runtime, as does the test. Thus the statement as a whole is broken (is it supposed to not even assign at all?), and the behavior of this line of code is considered undefined.
However, local
is very different. From perlsub (my emphasis)
A
local
modifies its listed variables to be "local" to the enclosing block,eval
, ordo
FILE --and to any subroutine called from within that block. A local just gives temporary values to global (meaning package) variables. It does not create a local variable.
Thus local
does something completely different than my
or our
; it saves the value of its target (global) variable for the rest of the block and restores it on exit from the block.
Also, since local
is a run-time operator there are no compilation-vs-runtime issues of declare + assign, as in my $x = 1
, so a postfix condition can be used. Consider
use warnings;
use strict;
use feature 'say';
my $flag = shift // 1;
our $var = 1;
{
local $var if $flag;
$var = 2;
say $var;
}
say $var;
When run with $flag
set (script.pl
) the local
-ization happens and the last print shows that the global our $var
has been preserved. With flag unset (script.pl 0
) this doesn't happen, the value of the global is not saved away for the block, and ends up overwritten.
With local $var = 2 if $flag;
neither the localization nor the assignment happens.
If only the local
statement itself is conditioned that must be done in the postfix manner since the effect of local
lasts only within the enclosing scope (so if ($f) { local $v }
does nothing for the rest of the code).
Doing this may change the code behavior radically, and possibly at a high level, based on a mere value of a single condition; I'd recommend to thread carefully with such code. This short program in particular only shows how a postfix condition can be used. Thanks to ysth and ikegami for comments.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With