No such thing as a small change PerlMonks

### Re^2: printing unitialized value of the 'do BLOCK'

by Eily (Monsignor)
 on Dec 17, 2019 at 15:18 UTC Need Help??

I already updated my post to say that you are probably right, but I'll say it again, straighter to the point: B::Deparse seems to confirm your interpretation as if (1) {BLOCK} is turned into do {BLOCK} (with BLOCK empty in rsFalse's example), and if (0) {} is turned into 0. So in the first case the if is optimized to return the value of the block, and in the second case the value of the EXPR.

++ to you obviously :)

• Comment on Re^2: printing unitialized value of the 'do BLOCK'

Replies are listed 'Best First'.
Re^3: printing unitialized value of the 'do BLOCK'
by Eily (Monsignor) on Dec 17, 2019 at 15:42 UTC

Fletch pointed out in the CB that using -x7 with B::Deparse gives the following confirmation:

```perl -MO=Deparse,-x7 -e "if (\$a) { &BLOCK }"
\$a and do {
&BLOCK
};
-e syntax OK
Where if (EXPR) {BLOCK} is equivalent to EXPR and do { BLOCK } which confirms haukex's interpretation. It's worth noting that if the two forms are equivalent, the latter is probably a lot less confusing when the output value is used.

> It's worth noting that if the two forms are equivalent, the latter is probably a lot less confusing when the output value is used.

It's also worth noting that B::Deparse can't always be trusted.

The clause of the if has the same scope like the inner block ( with if (CLAUSE) {BLOCK} )

```  DB<3> use strict; my \$x=3; if (my \$x =1) { print \$x }
1
DB<4> use strict; if (my \$x =1) { print \$x }; print \$x
Global symbol "\$x" requires explicit package name (did you forget to d
+eclare "my \$x"?) at (eval 13)[C:/Perl_524/lib/perl5db.pl:737] line 2.

DB<5>

but Deparse fails to cover this with -x7

```>>perl -MO=Deparse,-x7 -e"if (my \$x =1) { print \$x }; print \$x"
my \$x = 1 and do {
print \$x
};
print \$x;                      # <-- no error under strict!
-e syntax OK

Cheers Rolf
(addicted to the Perl Programming Language :)
Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

Very nice, thank you!

Hey!

So it means that an 'if' statement in function/RHS context returns the last expression evaluated! And this isn't documented I guess.
I guess newcomer would expect to get a 1 or ''/0 as a return value of 'if', but he can get also an 'undefined'. E.g. print do { 3 if undef };

.=
Interestingly, only one of these lines gives a warning:
```print do { 3 if () };
print do { () };
> Interestingly, only one of these lines gives a warning:

because the second one returns an empty list, which is a legal use of print.

```C:\WINDOWS\system32>Perl -MData::Dump=pp -e "pp do{3 if ()} "
undef

C:\WINDOWS\system32>Perl -MData::Dump=pp -e "pp do{()} "
()

Cheers Rolf
(addicted to the Perl Programming Language :)
Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

Re^3: printing unitialized value of the 'do BLOCK' (updated)
by haukex (Chancellor) on Dec 17, 2019 at 15:27 UTC

I remember this particular factoid because it has bothered me in the past that the return value of if isn't more clearly documented. I also know there was an old bug report in RT (not by me) to improve the docs that I'm having trouble finding right now as well :-/ I'm kind of busy right now so I'll report back on this later.

Update: The issue I was thinking of is this one: perlsub should be more explicit when an implicit return encounters an if(){} statement, where davido suggests this text for perlsub instead:

If no return is found and if the last statement is an expression, its value is returned. If the last statement is an if( CONDITION ) { BLOCK } construct, the value of the return value will come from BLOCK if CONDITION is true, or from CONDITION if CONDITION is false. Relying on this behavior is detremental to code legibility. If the last statement is a loop control structure like a foreach or a while, the returned value is unspecified.

Fixed tpyo

I remember this particular factiod because it has bothered me in the past that the return value of if isn't more clearly documented

Because it's not an expression. Expressions evaluate to a value, not statements. Nothing ever wants the value of an if statement.

Quote perlsub (for subs, but the same applies to do BLOCK):

If no return is found and if the last statement is an expression, its value is returned. If the last statement is a loop control structure like a foreach or a while, the returned value is unspecified. The empty sub returns the empty list.

An if statement isn't a "loop control structure", but more importantly, it's not an expression either. One shouldn't place an if statement as the last statement of a block from which we expect a value.

That said, people do use if statements that way, and the result has been quite predictable. (Update: Mostly predictable. Exception) The last expression evaluated during the course of the processing of the if statement is the resulting value.

```my \$x = 1;
if (\$x) {
f();      # f() is the last expression evaluated.
} else {
g();
}
```my \$x = 0;
if (\$x) {
f();
} else {
g();      # g() is the last expression evaluated.
}
```my \$x = 0;
if (\$x) {    # \$x is the last expression evaluated.
f();
}
```my \$x = 0;
if (\$x == 1) {
f();
} elsif (\$x == 2) (    # \$x==2 is the last expression evaluated.
g();
}

The same goes for while statements, until statements, and bare loops ({ }). Foreach loops are obviously different (since the iterator is hidden from us).

Updated

Because it's not an expression. Expressions evaluate to a value, not statements. Of course, Perl has the oddity that a value can be expected from any statement, but you get weird results if the last statement of a sub or do block is such a statement.

The reason it bothered me is that the return value of given is explicitly documented:

When a given statement is also a valid expression (for example, when it's the last statement of a block), it evaluates to: ...

But of course given is experimental, and I thought it would be nice if it was more clearly defined for the backwards-compatible if.

One shouldn't rely on that.

I'm aware of that for for, but not for if. Source?

Nothing ever wants the value of an if statement.

A plain if? Probably not. An if/elsif/else statement though?

```my @classifications = map {
if     (\$_ > 0)  { 'positive' }
elsif  (\$_ < 0)  { 'negative' }
else             { 'zero'     }
} @numbers;

Yes, you can write that using the ternary operator, but if/elsif/else can sometimes be clearer.

Thank you for visual explanations.

I learned to use 'do { if( ... ){ ... }else{ ... } }' years ago after reading "The do Block" in the book "Intermediate Perl", Chapter 3.
Few days ago I forgot to use 'do { ...else{ } }' and got unexpected (for myself) results, later I played with minimized case which I posted here.

And, after examples and explanations, it is interesting that expression inside opposite (= unless) statement is evaluated with negation:
```my \$x = 1;
unless (\$x) {    # '\$x' is NOT the last expression evaluated, but '!(
+\$x )' is.
f();
}
Upd.: My comment seems not to be truth. See further discussion - Re^6: printing unitialized value of the 'do BLOCK' proceeded by ikegami.

Create A New User
Node Status?
node history
Node Type: note [id://11110284]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (3)
As of 2020-05-27 02:18 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
If programming languages were movie genres, Perl would be:

Results (152 votes). Check out past polls.

Notices?