Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Re: printing unitialized value of the 'do BLOCK' (updated)

by haukex (Archbishop)
on Dec 17, 2019 at 15:06 UTC ( [id://11110282]=note: print w/replies, xml ) Need Help??


in reply to printing unitialized value of the 'do BLOCK'

For me it is strange that 'scalar do {};' and 'scalar do { if( 0 ){} };' have different outputs, as the codes look equivalent. Can someone explain a difference in the output?

if (EXPR) BLOCK returns either the value of BLOCK, or that of EXPR if it is false. I am certain it's mentioned somewhere in passing in the Perl docs, but I'm having trouble finding it at the moment; I'll update when I do.

Update: The text I was thinking of is in perlsub:

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.

This "implicit return" stuff applies to do as well as to subs. As explained further down in this thread, in if (EXPR) BLOCK, when EXPR is false, the value of the last expression is that of EXPR, which is therefore returned.

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

    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 :)

      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 { () };

      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

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11110282]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (3)
As of 2024-04-23 23:40 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found