Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl “do { … } if …” as expression

my $x = do { 3; } if 1; say $x # works

my $x = (do { 3; } if 1); say $x # syntax error

How come? If the do block is an expression, why can't it be parenthesised? If it's not, how does the first one parse?

like image 629
usretc Avatar asked Apr 08 '26 04:04

usretc


2 Answers

A compound statement used for flow control (if BLOCK), as well as one with the statement modifier (used here, the postfix if), cannot appear inside parenthesis.

This restriction makes sense since such a statement may or may not return a value

if executes the statement once if and only if the condition is true.

(original emphasis)


A side note. The first example runs without warnings but it has undefined behavior, what must be avoided. From the end of the section Statement Modifiers in perlsyn

NOTE: The behaviour of a my, state, or our modified with a statement modifier conditional or loop construct (for example, 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.

(original emphasis)

Any instances of this should be rewritten, and Perl::Critic has a policy for it, making it easier to find them

like image 84
zdim Avatar answered Apr 10 '26 18:04

zdim


It's not that the do that's the problem, it's the postfix if. That postfix can't appear inside the parens:

$ perl -E 'my $x = ( 1 if 1); say $x'
syntax error at -e line 1, near "1 if"
Execution of -e aborted due to compilation errors.

Instead, you can use the conditional operator ?: with a do in one of the branches:

$ perl -E 'my $x = ( time % 2 ? do { 1 } : () ); say $x'
like image 44
brian d foy Avatar answered Apr 10 '26 16:04

brian d foy