Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

Code blocks with ternary operator or trailing conditionals

by puterboy (Scribe)
on Feb 09, 2014 at 02:25 UTC ( [id://1074082]=perlquestion: print w/replies, xml ) Need Help??

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

I am looking to use compound statements (a.k.a. code blocks) with the ternary operator and also with trailing if/unless conditionals. E.g.
{statement 1; statement 2} if condition;
condition ? {statement 1; statement 2} : {statement 3; statement 4}
However this gives me errors...

I know I could use full if/else (or unless/else) constructs but the form above would be cleaner for me when the statements are very short.

Replies are listed 'Best First'.
Re: Code blocks with ternary operator or trailing conditionals
by kcott (Archbishop) on Feb 09, 2014 at 04:13 UTC

    G'day puterboy,

    Trying to force multiple statements and conditions into one line of code does not necessarily result in "cleaner" code. You leave yourself open to all sorts of precedence and syntax issues.

    Future maintenance can also become a headache: instead of simply adding "statement 3;" to a well laid out block of code, you may need to deal with bugs due to unforeseen precedence issues or you may need to rewrite that whole block because "statement 3;" introduces syntactical incompatibilities.

    Code like:

    if (condition) { statement 1; statement 2; } else { statement 3; statement 4; }

    will almost certainly be more readable and maintainable than a syntactically correct version of:

    condition ? {statement 1; statement 2} : {statement 3; statement 4}

    Having said that, here's two ways that you might have written your first example:

    $ perl -e 'print "hello\n" and print "bye\n" if 1' hello bye
    $ perl -e 'print("hello\n"), print "bye\n" if 1' hello bye

    Here's how you might have handled the ternary example (using my previous example you should be able to see a second way to do this):

    $ perl -e '1 ? (print "hello\n" and print "bye\n") : (print "hello2\n" + and print "bye2\n")' hello bye

    Had I needed to write code like this, I probably would have used do {...} blocks as shown by Athanasius (in fact, that was my first thought before scrolling down and seeing that solution).

    You should also familiarise yourself with the precedence issues explained in the ternary operator documentation.

    -- Ken

      Based on the sage advice in this thread and my own past experience, I have decided on the following (personal approach):

      1. For very simple, repetitively used, definitively *scalar* compound statements with if/unless, use the comma operator to allow for single line visually cleaner code. e.g,
      $error = "Bad result", next unless defined $result;
      2. Consider using the 'do' statement if the compound statement is still very short and the code will be visually cleaner and easier to read but the operators are non-scalar, so the comma operator can't be used. e.g.,
      do{push @results, $item; next} if defined $item;
      Although, that may not be much better/cleaner than:
      if(defined $item){push @results, $item; next}
      3. Otherwise use the full-blown if/else alternative

      Of course, others will choose other options...
        Use parentheses for those list-eating functions.
        push(@results, $item), next if defined $item;
      Indeed, I have tried these in the past -- but:
      1. The 'and' method requires one to be very careful about return values -- making sure you have the logic right the first time and that the logic never changes or has exceptions (as you and others have pointed out).
      2. The comma method is great (and even works with the ternary operator, if you use parentheses similar to how you did when using 'and'). However, this only works with scalar statements and can create real issues/confusion with operators that can operate on lists (like print).

      So thanks for showing these options -- even though I have mostly shied away from them -- due to the syntax/grammer issues you and others have raised. Thanks!!!
Re: Code blocks with ternary operator or trailing conditionals
by Athanasius (Archbishop) on Feb 09, 2014 at 02:49 UTC

    Just use do blocks:

    #! perl use strict; use warnings; my $x = 42; do { print "Hello "; print "world!\n"; } if 7 < $x; 43 > $x ? do { print "Yes, "; print "it is!\n"; } : do { print "No, "; print "it isn't!\n"; };

    Output:

    12:46 >perl 865_SoPW.pl Hello world! Yes, it is! 12:46 >

    See do.

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      Thanks - I am aware of 'do' -- just was hoping there was a way to 'do' it without it...
        ... a way to 'do' it without it...

        I wouldn't say this is a better way (in fact, as kcott has pointed out below,  if { ... } else { ... } syntax is better for what you seem to want than this or a do block), but it's a way:

        c:\@Work\Perl\monks>perl -wMstrict -le "my $x = 42; ;; sub { print qq{Hello }; print qq{world!}; }->() if 7 < $x; ;; 43 > $x ? sub { print qq{Yes, }; print qq{it is!}; }->() : sub { print qq{No, }; print qq{it is not!}; }->() ; " Hello world! Yes, it is!
Re: Code blocks with ternary operator or trailing conditionals
by Plankton (Vicar) on Feb 09, 2014 at 02:28 UTC
    What errors do you get? And how about posting the actual code or part of the actual code?
      perl -e 'print "hello\n" if 1' hello
      vs.
      perl -e '{print "hello\n"; print "bye\n"} if 1' Execution of -e aborted due to compilation errors. syntax error at -e line 1, near "if 1"
      And:
      perl -e '1 ? print "hello1\n" : print "hello2\n" if 1' hello1
      vs.
      perl -e '1 ? {print "hello1\n"; print "bye1\n"} : {print "hello2\n"; p +rint "bye2\n"}' syntax error at -e line 1, near "; print" syntax error at -e line 1, near ""bye2\n"}" Execution of -e aborted due to compilation errors.
Re: Code blocks with ternary operator or trailing conditionals
by Anonymous Monk on Feb 09, 2014 at 09:08 UTC
    Just use an if...else. The ternary operator is not meant for full statements.

    If I had to put them all on a single line, I'd use something like this, but you'll have to be careful of false values:

    1 and print "hello1\n" and print "bye1\n" or print "hello2\n" and prin +t "bye2\n"
    ...That's awful in terms of style, though. Just use an if statement.
Re: Code blocks with ternary operator or trailing conditionals
by sundialsvc4 (Abbot) on Feb 09, 2014 at 15:10 UTC

    I’ll agree rather strongly with kcott and the others on this one:   when the language fairly-obliges you to use a few “extra” keywords, do so.   Why?   Maybe because these “extra few” symbols serve to bypass ambiguities in the underlying grammar, such that there now becomes, and in the general(!) case, only one way that your intentions might be evaluated by the parser and so on.   Every language has characteristics like this, somewhere in the any every language.   There will be a “right way” that might superficially seem odd or inconvenient.   Why did they require that extra stuff?   Maybe just because it made the grammar necessarily-stronger in a place where it truly needed to be stronger.

    Also, think carefully about long-life maintainability of the code ... because computer software does have a very long life-span during which it will pass through many hands besides your own.   It could well be that a future change to your code, if written in this way, could have unintended consequences that do not result in a syntax-error.   (And this whether you were the one making the change, or not.)     “Two paths diverged in a snowy wood,” and both were equally valid, and [Perl...] took the other one and raised no yellow flags.   Maybe they affect the direct code-line that you are modifying at that time, but maybe they do not ... and does your project really have an all-encompassing test suite that is constantly maintained along with the code?   Didn’t think so.   So, this is just something that you should avoid as a matter of course, because hair-follicles are a precious thing . . .

      Thanks for the good lesson. I don't disagree with you (or the others who have answered similarlY) at all.

      My reason for asking was not out of coding "laziness" but rather to seek new grammatically *valid* tricks.

      The cool thing about Perl is that I find more often than not that there are cleaner/better ways of doing things than are available in other C-like languages. Hence, my reason for asking - to learn. Thanks!!!

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (5)
As of 2024-04-25 17:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found