Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Possible precedence issue with control flow operator

by will_ (Scribe)
on Jan 13, 2020 at 11:04 UTC ( #11111352=perlquestion: print w/replies, xml ) Need Help??

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

The following code gets a warning: Possible precedence issue with control flow operator
return something() or croak "something didn't work";
But I've always used or for control flow like "die" or "return", and || for logical expressions where the result doesn't affect which path the program takes (in that line).

Is this better? If not, what's the best way to write it?
return something() || croak "something didn't work";

 

ɹǝʞɔɐɥ lɹǝd ɹǝɥʇouɐ ʇsnɾ

Replies are listed 'Best First'.
Re: Possible precedence issue with control flow operator
by Eily (Monsignor) on Jan 13, 2020 at 11:23 UTC

    I must admit that I'm a little surprised myself, but it turns out that or's precedence is so low that it is actually lower than return (probably because return is treated as a list operator). Which leads to the following result:

    perl -MO=Deparse -e "sub test { return int(rand(2)) or print 'Nope' }" sub test { print 'Nope' unless return int rand 2; } -e syntax OK
    I'm pretty sure this is not what you meant, because this would somehow try to do something in the sub after returning from it. I'm also not exactly sure what the return value of return itself would be :P.

    Two ways to do what you want (beyond the one you already proposed), either with a temp variable:

    my $result; $result = something() or croak "Something went wrong"; return $result;
    Or, if this is the last line of your sub, you could remove the return altogether (if that's compatible with your coding rules):
    sub mySub { ... something() or croak "Times are a'croaking"; }
    The right way is the one that you like the most (again, respecting whatever coding rules should apply).

      When you're trying to suss out precedence problems the "-p" flag to B::Deparse can be useful to get it to shove in explicit parens everywhere.

      $ perl -MO=Deparse,-p -e "sub test { return int(rand(2)) or print 'Nop +e' }" sub test { ((return int(rand(2))) or print('Nope')); } -e syntax OK

      The cake is a lie.
      The cake is a lie.
      The cake is a lie.

      There's a third way: Parens can be used to override precedence.

      return ( something() or croak "Times are a'croaking" );
      A return is evaluated in the context of the sub's caller.

      so this variant

      my $result; $result = something() or croak "Something went wrong"; return $result;

      is safer (resp. only correct) if it's supposed to be a scalar.

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

Re: Possible precedence issue with control flow operator
by 1nickt (Abbot) on Jan 13, 2020 at 11:27 UTC

    How can return fail? Perl's warning is spot-on. If you want to croak when the return value isn't true, that needs to be associated with the sub call, not the return call. Precedence takes care of that, and you can still use or if you add parens:

    $ perl -Mstrict -wE'sub foo{} sub bar{return foo() or die "died"} bar( +)' Possible precedence issue with control flow operator at -e line 1.
    $ perl -Mstrict -wE'sub foo{} sub bar{return foo() || die "died"} bar( +)' died at -e line 1.
    $ perl -Mstrict -wE'sub foo{} sub bar{return (foo() or die "died")} ba +r()' died at -e line 1.

    Hope this helps (but you already got it I reckon...)!


    The way forward always starts with a minimal test.
Re: Possible precedence issue with control flow operator
by davido (Cardinal) on Jan 13, 2020 at 18:24 UTC

    In the first case consider what is happening:

    (return something()) or (croak "Something didn't work.\n");

    return will always return. Interestingly, it may return a false value (return 0; or return undef or return ''; or even return ()). But it will certainly return. Once it has returned, the subroutine is done. There's no way to ever reach the low precedence 'or'. It's like hanging up the phone before you ever hear the other party ask a question.

    In the second example, it's like this:

    return (something() || croak "Something didn't work.");

    Now something() is evaluated, and if it is false, then the || evaluates the righthand side, which is the croak call. Croak throws an exception and consequently control is never handed to the return.

    Before return can run, its arguments must be evaluated. In the first example its argument is something()'s return value. In the second example, the expression is the entire construct including the || croak.


    Dave

Re: Possible precedence issue with control flow operator
by LanX (Archbishop) on Jan 13, 2020 at 17:11 UTC
    It's not clear to me what you really wanted.

    When in trouble with perlop precedence always use parentheses.

    The 1. variant

    > return something() or croak "something didn't work";

    equals

    ( ( return something() ) or ( croak "something didn't work" ) );

    But doesn't make much sense, because the or-branch is never reached.

    A "normal" return almost never fails, and if return fails, the program dies right away:

    > perl return __END__ Can't return outside a subroutine at - line 2.

    (update: one might argue that the former shouldn't even compile, but there are probably use-cases in combination with do FILE )

    The 2. variant

    > return something() || croak "something didn't work";

    equals

    return ( ( something() ) or ( croak "something didn't work" ) );

    which looks a bit strange but is somehow possible.

    still Carp::croak() means to die

    # die of errors (from perspective of caller) croak "We're outta here!";

    so returning the value of croak doesn't really make sense either.

    update

    The latter means mixing two very different control flows in one line ... irk.

    In the spirit of PBP : "make control flows immediately clear!", mixing two is quite confusing for the reader.

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

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://11111352]
Approved by marto
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (4)
As of 2020-01-27 18:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Notices?