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

Hi, could someone please explain to me how is this statement executes? I'm not quite understand it.

for ... { next unless $cell; }

Does it means:

if (!$cell) {next}

Replies are listed 'Best First'.
Re: next unless condition
by haukex (Archbishop) on Mar 31, 2016 at 18:43 UTC

    Hi hankcoder,

    Yes, that's essentially what it means - next unless $cell; does the same as unless($cell) {next}, and unless is just an if with the condition inverted, as in if (not ...) .... This is covered in Compound Statements and Statement Modifiers.

    Another way to write that is $cell or next; which means that if $cell has a true value, the or expression will be true, so it "short-circuits" and does not need to execute the right hand side, next. If $cell is false, the or needs to check its right argument for truth, so the next is executed.

    You can see this equivalence yourself with B::Deparse:

    $ perl -MO=Deparse,-p -e 'next unless $cell' ($cell or (next));

    Hope that helps,
    -- Hauke D

      I was with you all the way until $cell or next;. That is a clever trick which doesn't convey intent and thus impedes understanding and maintenance.

      From an understanding and maintenance point of view:

      next if !$cell;

      is succinct and clear and thus maintainable. In general I find if with a negated expression clearer than unless, especially if the expression is non-trivial. It also scales better so there are fewer surprises during maintenance if the expression needs to change.

      Update: s/cleaver/clever/. Thanks kennethk - I'd like to claim the pun, but it wasn't.

      Premature optimization is the root of all job security

        Hi GrandFather,

        The reason I added the explanation of $cell or next; to my post was because I first saw the output of B::Deparse, so perhaps the narrative of my post would have been better that way around - "here's what B::Deparse gives you, and here's what it means".

        Personally, I find $cell or next; is short enough to be readable in all three variations (next unless $cell;, next if !$cell;), and if I was writing it I'd lean towards next unless $cell;. If either side of the or had been more complex or becomes more complex later, then I might agree with you. As for the general case of if/unless vs. and/or, I write it however I find most readable. For example, sometimes I find $cond or die "some long error message" better than die "some long error message" unless $cond, even if the latter is wrapped on two lines. Or, I've recently found myself writing $DEBUG and print "..." more often, I find it helps me skip over those lines quicker when I'm skimming the code. On the other hand, if the condition is more complex, I'd start considering maintenance costs (usually precedence issues creeping in), and I'd probably switch over to the "safe" if (...) {...}. And it's a matter of TIMTOWTDI and taste too, I guess :-)

        Regards,
        -- Hauke D

        Update: Fixed one of the code samples.

        GrandFather: I was with you all the way until $cell or next;. That is a cleaver trick which doesn't convey intent and thus impedes understanding and maintenance.

        In what way does it not convey intent?

        In what way is it unclear?

        It also scales better so there are fewer surprises during maintenance if the expression needs to change.

        How does it scale better? If you need to change the expression, why can't you change the entire line?

      Over the last 20 years, I have seen this construct written in the very perlish manner of :

      $cell || next;

      which is the same as:

      $cell or next;

      The explanation that I have "heard" in the past is that this performed faster than other functionally equivalent alternatives. I have always been skeptical of this POV and too lazy to actually test it

      I personally like the way next unless $cell reads for loop control and often use this construct. In general, I am not a big fan of unless and general use If ( not $cell ) with the exception of loop control. My rationale behind this is that I think it is easier to read and comprehend for someone who comes behind me to maintain any code that I have created. Please note the use of belief here. I do not purport that to be a fact.

      lbe

        The explanation that I have "heard" in the past is that this performed faster than other functionally equivalent alternatives.

        That's not the case.

        $ perl -MO=Concise,-exec -e'f() unless $x' 1 <0> enter 2 <;> nextstate(main 1 -e:1) v:{ 3 <#> gvsv[*x] s 4 <|> or(other->5) vK/1 5 <0> pushmark s 6 <#> gv[*f] s/EARLYCV 7 <1> entersub[t3] vKS/TARG,1 8 <@> leave[1 ref] vKP/REFC -e syntax OK $ perl -MO=Concise,-exec -e'$x or f()' 1 <0> enter 2 <;> nextstate(main 1 -e:1) v:{ 3 <#> gvsv[*x] s 4 <|> or(other->5) vK/1 5 <0> pushmark s 6 <#> gv[*f] s/EARLYCV 7 <1> entersub[t4] vKS/TARG,1 8 <@> leave[1 ref] vKP/REFC -e syntax OK
        There is a difference in operator precedence between $cell || next and $cell or next, so they're not quite the same. While they're effectively identical in this case, even the minor modification of adding an assignment results in $x = $cell || next and $x = $cell or next behaving differently.

        The efficiency explanation you've heard is accurate when dealing with extremely-close-to-the-metal languages and non-optimizing compilers, since testing whether a memory location already holds the value 0 is one of the fastest tests you can do at the machine level. But optimizing compilers are smart enough to figure out for themselves that if (not $cell) ... is equivalent to $cell || ... while still allowing you to write it the more readable way, and Perl is so far from the metal that these kinds of concerns are completely inapplicable anyhow.

        Hi lbe,

        Yes, $cell || next; is yet another one to add to the list of ways to do it :-) (Although it's probably easier to get bitten by precedence issues on that one so personally, I'd avoid it.)

        if (...) {...} is definitely what I'd use if the condition or the statement becomes more complex. For example, I've often written code something like if ($x && $y) { warn "skipping b/c foo"; next }

        Regards,
        -- Hauke D

      Thanks Hauke D, that helps a lot.

Re: next unless condition
by Discipulus (Canon) on Apr 01, 2016 at 07:32 UTC
    This remember me Untillian Headache or about the semantic of until

    Infact english conjunctions as Perl keywords are easy understandable but in the negative forms ( unless and until ) introduce some semantic problem in the heads of non native english peoples.

    Logically speaking see tmharish's answer about De Morgan's laws.

    For readability i'd go with next if !$cell; or with $cell or next;

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
      Nice!++ I mostly upvote questions and initiates, but not today :D