http://www.perlmonks.org?node_id=773703

zigdon has asked for the wisdom of the Perl Monks concerning the following question:

Perlsub talks about subroutine return values:

A "return" statement may be used to exit a subroutine, optionally specifying the returned value, which will be evaluated in the appropriate context (list, scalar, or void) depending on the context of the subroutine call. If you specify no return value, the subroutine returns an empty list in list context, the undefined value in scalar context, or nothing in void context. If you return one or more aggregates (arrays and hashes), these will be flattened together into one large indistinguishable list.

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.

Based on that, I thought I understood subroutine return values - but now I'm not sure anymore. Consider the following:

sub test { print "in test!"; return if 1 } if (&test) { print "true" } else { print "false" }
Running this, I get:
in test!
false
Which made sense to me - we're returning an empty list, which is false. Fine.

But I expected the behaviour to be flipped if I change the 1 to 0. Since 'return if 0' doesn't fire, we don't have an explicit return value, and so the sub should evaluate to the whatever the last statement that executed evaluated to - in this case, the print, which should be true.

But that wasn't what happened at all. I had to *comment out* the 'return' line to get the true value I was expecting.

So what am I missing here? Does the 'if' line count as a statement that evaluates to false?

-- zigdon

Replies are listed 'Best First'.
Re: return if 0
by ikegami (Patriarch) on Jun 22, 2009 at 17:42 UTC
    The last statement executed is return if 0;. The return may not have been executed, but the statement did. An if statement whose condition evaluates to something false, evaluates to that something.

    (I believe the last sentence is undocumented behaviour.)

      perl -E 'sub result { return 1 if "0" } say result'
      yields
      0
      and
      perl -E 'sub result { return 1 if "0 but true" } say result'
      yields
      1
      thus proving your statement :-D
      []s, HTH, Massa (κς,πμ,πλ)
        Not really, but the following does:
        $ perl -MData::Dumper -e'print Dumper sub{return 1 if $_[0]}->(undef)' $VAR1 = undef; $ perl -MData::Dumper -e'print Dumper sub{return 1 if $_[0]}->(0 )' $VAR1 = 0; $ perl -MData::Dumper -e'print Dumper sub{return 1 if $_[0]}->("0" )' $VAR1 = '0'; $ perl -MData::Dumper -e'print Dumper sub{return 1 if $_[0]}->("" )' $VAR1 = '';

        Update: Switched to DD to show the difference between string zero and numerical zero.

        Interesting! The last expression evaluated is the string "0". That's false, so the return doesn't fire, but the "0" is actually returned.

        Cool example, thanks!

        -- zigdon

Re: return if 0
by ambrus (Abbot) on Jun 23, 2009 at 07:13 UTC

      No, it doesn't.

      #!perl -l sub test_c { $x=2; return 1 if 0; } sub test_v { $x=2; return 1 if $_[0]; } print test_c(); print test_v(0);
      0 0

      If an optimisation changes Perl's behaviour, it would be a bug.

Re: return if 0
by TGI (Parson) on Jun 24, 2009 at 19:02 UTC

    My response is not really related to the question, but to the sample code.

    In fact my response is nearly identical to this one I posted a while ago: Re: Delete files with Perl in Windows

    In short: don't use &foo to call a subroutine, unless you really mean it. See the linked node for more info.

    BTW, keep experimenting and asking questions. It's a great way to learn.


    TGI says moo

Re: return if 0
by FloydATC (Deacon) on Jun 22, 2009 at 19:05 UTC
    return if 0; is interpreted as if (0) { return; } which will never happen.

    -- Time flies when you don't know what you're doing
      Not true. The return is never executed, but like the OP noticed and we've been explaining, the statement *is* executed. How else can it be known whether the return should be executed or not?

        To be fair, it wouldn't be insane for the compiler to know that the block can never execute, and just remove it completely.

        Except for the part that it has unexpected consequences, as we've been discussing.

        -- zigdon

        Perhaps I was a bit unclear; I meant to say the "return" will never happen because 0 will never be true.

        -- Time flies when you don't know what you're doing