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

I'm very new to Perl and I saw a statement like this:
return if ($i > 1);
I've never seen that syntax before, but does it work with things besides return? It's just strange to me because the code to execute goes before the if, but it's very common in real speech.

Replies are listed 'Best First'.
Re: Are there any other statements that are like return if...?
by toolic (Bishop) on Jun 27, 2008 at 14:54 UTC
    does it work with things besides return?
    Yes. You can read about it in perlsyn. Look at "Statement Modifiers".
Re: Are there any other statements that are like return if...?
by pc88mxer (Vicar) on Jun 27, 2008 at 14:50 UTC
    There' also the same kind of statement using if's cousin, unless:
    return unless ($i <= 0);
    and there's also while, until and for:
    print "i = $i\n" while ($i++ < 10); $i = 0; print "i = $i\n" until ($i++ >= 10); print "$_\n" for (1..10); # note: for my $i ... doesn't work
Re: Are there any other statements that are like return if...?
by jethro (Monsignor) on Jun 27, 2008 at 15:00 UTC
    The father of perl, Larry Wall, is also a linguist. Prepare to meet more examples of this as you get to know perl.

Re: Are there any other statements that are like return if...?
by Herkum (Parson) on Jun 27, 2008 at 15:09 UTC

    It also works with trinaries as well.

    return $i == 1 ? 'red' : $i == 2 ? 'blue' : $i == 3 ? 'green' : $i == 4 ? 'yellow' : 'white';

    However, you should only use this sort of syntax if the syntax is short. It easier for a person to read columns up and down then it is from something that goes from one end of the page to the other. Lets change my example to so you see what I mean.

    return $i == 1 ? 'red': $i == 2 ? 'blue' : $i == 3 ? 'green' : $i +== 4 ? 'yellow' : 'white'; # God forbid print "This is my very long string that I wish to print out to display + my message on the screen but only when I want it too!" if $i == 1;

    The last one is just asking for trouble because you will probably be looking at the print on the front and not notice the if statement on the end.

      Well, for equality testing, I'd use a hash (or array for dense numerical indexes) lookup.
      my @COLORS = qw( white red blue green yellow ); return exists $COLORS[$i] ? $COLORS[$i] : $COLORS[0];

      But if you need logical checks that are more complex than equality, the ternary chain you show is quite handy:

      return $i < 5 ? 'red' : $i < 20 ? 'blue' : $i%3 == 0 ? 'green' : $i%5 == 0 ? 'yellow' : 'white';

      And you are absolutely correct about the importance of formatting with this construct.

      As for the trailing 'if','unless' and 'or', formatting is key here as well. I tend to bring those onto a separate line:

      print "This is my very long string that I wish to print out to display + my message on the screen but only when I want it too!" if $i == 1; # the very common 'or die' idiom with a big brutish open() open ( my $filehandlewithalongname, $modevariablewithalongname, $pathvariablewithalongname ) or die "Unable to open file $pathvariablewithalongname: $!\n"; # 'or die' again with a smaller, kinder open: open ( my $fh, $mode, $path ) or die "Unable to open $path: $!\n"; # is equivalent to this 'die unless' # which I have never seen used with open(). die "Unable to open $path: $!\n" unless open ( my $fh, $mode, $path ) # however, 'die unless' is common with value checks. die "Illegal value: $rotifer\n" unless $rotifer =~ /^is ok$/; # as is 'die if' die "Illegal value: $rotifer\n" if $rotifer =~ /^is not ok$/;

      I think the main difference between 'x or y' and the equivalent 'y unless x' is emphasis. In the former, the emphasis is on the statement 'x'. Whereas in the latter, the emphasis is on the statement 'y'. Choice of form is therefore indicated by what you believe will express your intent most clearly.

      Another thing worth noting here is that one can use 'x and y' as a stand-in for 'y if x'. I avoid 'x and y' because the short circuit evaluation of 'and' is, in my opinion, not intuitive. If I want to emphasize the 'x' in the code, I just use the good old 'if(x) { y }' form instead of 'x and y'.


      TGI says moo

Re: Are there any other statements that are like return if...?
by shoness (Friar) on Jun 27, 2008 at 19:07 UTC
    Realize that "important stuff" needs to be on the left side of the page because few people have the time to read entire lines to figure out what's going on. ☺

    Using this "backwards" style, your code intent stays more visible.

    For example, it's common to do this for something like:

    print "Here we are..." if $debugging;
    Often I'll decide one way or the other based on whether it's a special case or normal case. Be careful though, since as others have pointed out, you can obscure intent as well. Mixing them up, as with this block, I find confusing at a glance. Changing the indentation can help.
    if ($unlikely_condition) { &do_that_voodoo; } &that_yoodoo if $typical_case;
    Cheers!
Re: Are there any other statements that are like return if...?
by jds17 (Pilgrim) on Jun 27, 2008 at 17:38 UTC
    Yes, it's plain Perl syntax, but e.g. the classic Perl Best Practices by Damian Conway as well as the corresponding Module Perl::Critic (which you can use as a code quality tool for your own code) are against such postfix contructs for readability and maintainability reasons, the sole exception being postfix if as in your example for simple control statements. (You can change the behaviour of Perl::Critic if you want to use it but disagree with this, see the documentation!)

    Personally I use postfix only in case the whole block fits in one line.

      Yeah, classic 2005
Re: Are there any other statements that are like return if...?
by GrandFather (Saint) on Jun 27, 2008 at 21:45 UTC

    As others have pointed out this is Perl's "statement modifier" idiom. Perl has many shorthand ways of achieving things and that is a large part of what gives Perl its power to be concise and clear.

    consider the following:

    my $filename = "$root/$path/$name"; open my $fileHandle, '<', $filename or die "Failed to open $filename: +$!"; print $fileHandle "$_: $results[$_]\n" for 1 .. $#results; print $fileHandle "Total: $results[0]\n";

    which deflares a variable in the middle of a file open statement, uses the "or die" idiom to check the result of an open, uses a for loop taking a range as a statement modifier and uses string interpolation to construct a file name from components and to build the strings to be printed.

    The result is concise, lucid and robust.


    Perl is environmentally friendly - it saves trees