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

our $cookingcounter = 350883; our $garlicbreadheadstart = 600; our $ovenempty = 0; my $holdtime = 0; if ( !$ovenempty || $test && ( 0 <= ( $holdtime = $cookingcounter + 60 * 90 - 356400 ) || 0 <= ( $holdtime = $cookingcounter + ( $garlicbreadheadstart - 60 * ( 60 + 15 ) ) - 356400 ) ) ) { die sprintf 'Main Dish or Appetizer Cooking: %d, hold for %d', $cookingcounter, $holdtime; }
Produces
Main Dish or Appetizer Cooking: 350883, hold for 0 at main.pl line 21.
Expected hold time to not be zero.

Replies are listed 'Best First'.
Re: Lazy conditional, skips assignment.
by roboticus (Chancellor) on Mar 25, 2015 at 19:50 UTC

    cheako:

    If the first clause of an AND is false, or if the first clause of an OR is true, there's no reason for perl to evaluate the right side of the expression. Side effects in expressions often have issues like this.

    In your case, it looks like you're just trying to pack too much stuff in a single conditional. When I look it over, I wonder what the heck it's doing. Yeah, I can figure it out, but I'd rather work on code that I can read, rather than decipher. Breaking it down into discrete units will make it simpler to read, and easier for you to debug, as well!

    Update: I think your code is probably trying to do this (roughly):

    our $cookingcounter = 350883; our $garlicbreadheadstart = 600; our $ovenempty = 0; sub hold_time { my $cookingcounter = shift; return 0 if $ovenempty and !$test; my $holdtime = $cookingcounter + 60*90 - 356400; return $holdtime if $holdtime > 0; $holdtime = $cookingcounter + ($garlicbreadstart - 60 * (60+15)) - + 356400; return $holdtime if $holdtime > 0; return 0; }

    Update 2: After seeing hdb's response, I adjusted my code so it wouldn't return in test mode even when the oven is empty.

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

Re: Lazy conditional, skips assignment.
by hdb (Monsignor) on Mar 25, 2015 at 20:00 UTC

    1. Wholeheartedly agree with roboticus.

    2. You did not tell us what $test is. I would imagine that you ignored the fact that && takes precedence over || and that you meant to say

    if ( ( !$ovenempty || $test ) # observe extra parentheses && ( 0 <= ( ...
Re: Lazy conditional, skips assignment.
by Laurent_R (Canon) on Mar 25, 2015 at 21:56 UTC
    Gosh, this code is really messy, and the wrong indentation really does not help. And, above all, when you use operators having almost the same precedence, you should use parentheses to clarify your intent.

    I simplified your code to this (in a one-liner type of execution):

    $ perl -e 'our $cookingcounter = 350883; > our $garlicbreadheadstart = 600; > our $ovenempty = 0; > > my $holdtime = 0; > if ( > !$ovenempty > || $test > && $holdtime = 1) > ) { > die sprintf "Main Dish or Appetizer Cooking: %d, hold for %d", $ +cookingcounter, $holdtime; > }' Main Dish or Appetizer Cooking: 350883, hold for 0 at -e line 11.
    As you can see, $holdtime is not assigned to 1. The important point is the precedence between || and &&. && has a higher precedence than ||. So that the preceding code can be interpreted as:
    our $cookingcounter = 350883; our $garlicbreadheadstart = 600; our $ovenempty = 0; my $holdtime = 0; if ( !$ovenempty || ($test && $holdtime = 1) ) { die sprintf "Main Dish or Appetizer Cooking: %d, hold for %d", $co +okingcounter, $holdtime; }
    In short, if !$ovenempty is true, none of the rest of the code is ever executed, because:

    - !$ovenempty evaluates to true,

    - and that's enough, we won't care about conditions grouped in a conditional having a lower priority.

    So that the rest of the code is not even executed.

    Je suis Charlie.
Re: Lazy conditional, skips assignment.
by vinoth.ree (Monsignor) on Mar 25, 2015 at 20:11 UTC
    Hi,

    I am little bit confused with your if condiction,here is the code I changed,

    our $cookingcounter = 350883; our $garlicbreadheadstart = 600; our $ovenempty = 0; my $holdtime = 0; if ( (!$ovenempty || $true) && ( 0 <= ( $holdtime = $cookingcounte +r + 60 * 90 - 356400) || 0 <= ($holdtime = $cookingcounter + ($garlic +breadheadstart -60 * ( 60 + 15 )) - 356400) ) ) { die sprintf 'Main Dish or Appetizer Cooking: %d, hold for %s', $cookingcounter, $holdtime; } else { printf 'Main Dish or Appetizer Cooking: %d, hold for %s',$co +okingcounter,$holdtime; }

    In if condition I have grouped (!$overempty || $true) Of course you did not tell us the $true variable value, and added else{} part. I think else part prints what you expect.


    All is well. I learn by answering your questions...
Re: Lazy conditional, skips assignment.
by locked_user sundialsvc4 (Abbot) on Mar 25, 2015 at 20:12 UTC

    Ditto.   “Perl Golf” is meant to be an idle amusement.   The best strategy is always to write code that is “abundantly clear.”   Make it obvious.   And, make it easily maintainable.   If I am, as in this case, “trying to calculate the cooking-time of a dish, with or without garlic bread,” then, please, don’t make me think about how you chose to say it.   Don’t introduce the risk that what you said is actually wrong ... or that, in order to make it do something else, I must put-at-risk everything that it is known to be doing correctly now.

    One way or the other, the Perl compiler will do its appointed job.   It will faithfully put into action exactly what you have written ... be it right or wrong.   “Golf speak” merely makes it harder ... much harder ... to know that it is right.