2

In perl, $x = if (0) {1} else {2} does not work.

$ perl -E'$x = if (0) {1} else {2}'
syntax error at -e line 1, near "= if"
Execution of -e aborted due to compilation errors.

This makes sense, because if conditionals are not expressions in Perl. They're flow control.

But then

my $x = do { if (0) {1} else {2} };

Does work! How come a do BLOCK can accept an if conditional? But assignment can not? It would seem in the above the flow control must either

  • know it's context in a do BLOCK
  • always act as an expression, but have that syntax disallowed by the parser.

Moreover given the simple facts above, what is the right way to describe an if-conditional that behaves like that? Is it an expression with a value? Is it flow-control construct that has no value after evaluation?

And, lastly, what modifications would have to be made to assignment to have it accept an if condition like a do BLOCK.

Evan Carroll
  • 78,363
  • 46
  • 261
  • 468
  • it's just not allowed syntax. every statement has context, and a do block supplies context, just like if the statement were the last in a subroutine. I don't see any benefit to allowing `$x = if ...`, seems unlikely to fly. if you want arbitrary statements in an expression, do blocks already exist for that. – ysth Feb 11 '20 at 01:55
  • 4
    The over-arching design is that perl has keywords that only are meaningful in certain contexts, and `if` is one of them - it can be only the start of a statement or a statement modifier, and neither of those are valid directly after an `=`. This is a parser distinction first and foremost. – Grinnz Feb 11 '20 at 02:38
  • 4
    Beyond that, the consideration of "what an if statement returns" is not always intuitive, so while you can find that out by putting it in a do block or the last statement of a subroutine, it's not something that should be encouraged to be used as a value. In fact it [commonly leads to bugs](https://metacpan.org/pod/Perl::Critic::Policy::Freenode::ConditionalImplicitReturn). – Grinnz Feb 11 '20 at 02:41
  • @Grinnz if you want to answer with that, I'll accept. – Evan Carroll Feb 11 '20 at 02:44
  • The [do BLOCK](https://perldoc.perl.org/functions/do.html) behavior is clear -- "_Returns the value of the last command..._". So it evaluates the condition under `if` and then executes code in the corresponding branch ... and returns the value of the last thing (that returned a value). And `2` is a fine expression to return a value from. So no mystery? – zdim Feb 11 '20 at 05:47
  • @zdim but the do-block ends with statement-level control flow, not with an expression (or whatever a "command" is). I consider that example to have undefined behaviour. – amon Feb 11 '20 at 06:02
  • @amon well yes, and I don't see such use as good practice. But the execution path is clear and we do end up with a "last statement" (that returns), and `do` promises to return _that_. May be an abuse but it appears clear what one gets out of it. (That is, unless the `if-else` _doesn't produce a value_ -- which is in general possible, so thus it may well be exactly UB as you say. However, `do` doesn't take a `return` either ...it's a little particular device, no?) – zdim Feb 11 '20 at 06:24
  • 3
    perl syntax distinguishes between expressions and statements, like many languages. though different languages have different lines between them; assignment is a statement in some languages, for example. but as a completely separate issue, in perl, statements do have return values (disregarding what may be documented or not); for instance, a block "statement" returns the value of its last statement; an if or unless that does not enter a block returns the value of the tested expression, while one that enters a block returns the value of the block; a for returns nothing. – ysth Feb 11 '20 at 07:15
  • If a block is a statement that returns a value, then what is an expression in to perl? How would one intuit that the ternary is an expression and not a statement that returns a value? I thought the ternary was an expression *because* it returned it a value. – Evan Carroll Feb 11 '20 at 14:17
  • Aiui... A statement is a grammatical unit that ➊ Signals to user and `perl` that its primary purpose in life is to have a side effect ➋ (At least notionally) returns a value that may sometimes be of use ➌ Suggests to `perl` there's no need to complain if the value is dropped on the floor. An expression ➊ Makes no claim about having a side effect ➋ Claims it will produce a useful value The `perl` grammar constrains where it'll accept an expression vs a statement, and the vocabulary provides particular statement and expression constructs, in order to provide a pleasant overall language. – raiph Feb 11 '20 at 15:43

2 Answers2

1

The only answer and commentary that addresses the question in a matter that brings clarity is Ginnz,

The over-arching design is that perl has keywords that only are meaningful in certain contexts, and if is one of them - it can be only the start of a statement or a statement modifier, and neither of those are valid directly after an =. This is a parser distinction first and foremost. Beyond that, the consideration of "what an if statement returns" is not always intuitive, so while you can find that out by putting it in a do block or the last statement of a subroutine, it's not something that should be encouraged to be used as a value. In fact it commonly leads to bugs. – Grinnz 11 hours ago

When Ginnz says parser distinction, I interpret that to mean that this isn't much worth pursing as a matter of clarity. What is valid after an = is simply not a if statement, and there is no real reason for it, except that it's how it is.

  • if conditional is a statement.
  • statement's return values.
  • assignment = expressly forbids statements on the right because it only accepts things in the expression class.
  • a do BLOCK can turn a statement into an expression.
Evan Carroll
  • 78,363
  • 46
  • 261
  • 468
  • "When Ginnz says parser distinction, I interpret that to mean that this isn't much worth pursing as a matter of clarity." I could say you haven't expressed yourself clearly with that statement. :) Aiui you've misinterpreted "parser distinction" as being specific to `if` but Grinnz didn't mean that. "What is valid after an `=` is simply not a `if` statement" Simply not *any* statement. "there is no real reason for it" I imagine the most people get confused the least if `=` rejects statements on the right (because many statements would do something thoroughly confusing if they were allowed). – raiph Feb 11 '20 at 16:13
  • "because many statements would do something thoroughly confusing if they were allowed" - right, like: `my $foo = foreach (@things) { say }` - you could wrap this in a `do {}` sure, but why? – Grinnz Feb 12 '20 at 16:42
0

Code inside DO block behaves differently. Perl interprets the code inside the curly brackets and outputs the result of the last command.


    #!/usr/bin/perl
    
    use Data::Dumper;
    
    my $x = do { { 1==1 } };
    my $y = do { { 1==0 } };
    print Dumper 1==0;
    print Dumper $x;
    print Dumper $y;

Read more about do: https://perldoc.perl.org/perlfunc#do

VPP
  • 41
  • 2