Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

order of operations with conditionals at the end

by BeneSphinx (Sexton)
on Mar 26, 2012 at 20:11 UTC ( [id://961737]=perlquestion: print w/replies, xml ) Need Help??

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

I like the natural flow of statements with the conditional at the end, but I'm having some difficulty understanding how it relates to order of operations, since if/unless/etc aren't listed in the Operator Precedence table (http://perldoc.perl.org/perlop.html#Operator-Precedence-and-Associativity) For example code like:
my $message = "Congrats" unless not defined $reward;
or
my @badVals; for my $val (@vals){ push @badVals, $val && next if isBad($val); print "$val is a good val.\n"; }
I would love to write these without parentheses because it's so nice to read, but I'm concerned about ambiguity. Wondering if you have any tips so I can try to at least get halfway there without danger... overall I'm curious about best practices for these kinds of statements.

Replies are listed 'Best First'.
Re: order of operations with conditionals at the end
by kcott (Archbishop) on Mar 27, 2012 at 01:34 UTC

    As a general solution to determining the order of operations, you can add the -p option to -MO=Deparse; you write it like -MO=Deparse,-p. This adds parentheses showing how perl parses your code.

    ken@ganymede: ~/tmp $ perl -Mstrict -Mwarnings -MO=Deparse,-p -E ' > my $message = "Congrats" unless not defined $reward; > ' Global symbol "$reward" requires explicit package name at -e line 2. -e had compilation errors. use warnings; use strict 'refs'; BEGIN { $^H{'feature_unicode'} = q(1); $^H{'feature_say'} = q(1); $^H{'feature_state'} = q(1); $^H{'feature_switch'} = q(1); } ((not defined(${'reward'})) or (my $message = 'Congrats')); ken@ganymede: ~/tmp $

    You'll see how you get an error about $message not being declared: this is different from not being defined. Here it is again with this variable being declared but left undefined.

    ken@ganymede: ~/tmp $ perl -Mstrict -Mwarnings -MO=Deparse,-p -E ' > my $reward; > my $message = "Congrats" unless not defined $reward; > ' use warnings; use strict 'refs'; BEGIN { $^H{'feature_unicode'} = q(1); $^H{'feature_say'} = q(1); $^H{'feature_state'} = q(1); $^H{'feature_switch'} = q(1); } my($reward); (defined($reward) and (my $message = 'Congrats')); -e syntax OK ken@ganymede: ~/tmp $

    Note differences between the error and error-free versions:

    • ((not defined(${'reward'})) or (my $message = 'Congrats'));
    • (defined($reward) and (my $message = 'Congrats'));

    See also:

    • perlrun: command switches, including -M
    • O: how -MO is expanded
    • B::Deparse: -p and other options

    -- Ken

Re: order of operations with conditionals at the end
by ikegami (Patriarch) on Mar 26, 2012 at 21:33 UTC

    if is not an operator. It's part of the syntax of an if statement. An if statement evaluates its condition first, then evaluates the rest if and only if the condition evaluated to something true.

    EXPR if CONDEXPR;

    is exactly the same as

    (CONDEXPR) and EXPR;

    By the way,

    my $var ... if ...;

    is not allowed. (Same goes for unless.) You should be using

    my $message; $message = "Congrats" if defined $reward;

    or

    my $message = $reward ? "Congrats" : undef;
      Not allowed?
      $ perl5.15.9 -wE 'my $x = 1 if 2; say $x // "???"' 1 $ perl5.15.9 -wE 'my $x = 1 if 0; say $x // "???"' ??? $
      I won't recommend it, but it is still allowed. I thought it started warning under certain conditions since 5.14, but I'm not able to reproduce it.
        The compiler does compile it, but it has been explicitly forbidden in the docs, and it has been so for far far longer than 5.14. (I'm guessing 5.6 or 5.8.)
Re: order of operations with conditionals at the end
by Tux (Canon) on Mar 26, 2012 at 20:44 UTC

    I hate statement modifiers. All except "for". Anyway, whenever in doubt place parens and/or check:

    $ perl -MO=Deparse -e'push @badVals, $val && next if isBad($val);' push @badVals, $val && next if isBad($val); -e syntax OK $ perl -MO=Deparse -e'(push @badVals, $val && next) if isBad($val);' push @badVals, $val && next if isBad($val); -e syntax OK $ perl -MO=Deparse -e'push @badVals, ($val && next) if isBad($val);' push @badVals, $val && next if isBad($val); -e syntax OK $

    Note that all parse the same, and thus probably do not do what you expected it to do. Compare to:

    $ perl -MO=Deparse -e'(push @badVals, $val) && next if isBad($val);' push @badVals, $val and next if isBad($val); -e syntax OK $ perl -MO=Deparse,-p -e'push @badVals, $val && next if isBad($val);' (isBad($val) and push(@badVals, ($val && next))); -e syntax OK

    update: added -p example after kcott's post.


    Enjoy, Have FUN! H.Merijn
Re: order of operations with conditionals at the end
by Khen1950fx (Canon) on Mar 26, 2012 at 21:49 UTC
    There are a couple of problems that I see. First, unless not is the same as if. Second, you have an undefined subroutine in isBad.
    #!/usr/bin/perl -l use strictures 1; no strict 'refs'; use Devel::SimpleTrace; print my $message = 'Congrats' if defined ${'result'}; my @badVals; foreach my $val (my(@vals)) { push @badVals, $val && next if isBad($val); print "$val is a good val"; } sub isBad {...}
Re: order of operations with conditionals at the end
by BillKSmith (Monsignor) on Mar 27, 2012 at 22:45 UTC
    The book "Perl Best Practices" recommends using conditionals only with the statements next, last, and redo.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (4)
As of 2024-04-25 14:28 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found