Re^2: next unless condition
by GrandFather (Saint) on Mar 31, 2016 at 21:06 UTC
|
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
| [reply] [d/l] [select] |
|
|
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.
| [reply] [d/l] [select] |
|
|
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?
| [reply] |
|
|
In what way does it not convey intent?
or is a boolean operator and implies an expression. Using if as a statement modifier is altogether different than forcing the role of implied if on the or operator.
In what way is it unclear?
By not conveying intent. Using or in the role of an if does not convey the intent of the code so the code is unclear.
How does it scale better? If you need to change the expression, why can't you change the entire line?
Completely replacing a chunk of code in order to make a small change to it means that the replaced code didn't scale at all!
The "It" in "It also scales better" was referencing if compared to unless. Using unless tends quickly to get into double negative land making it harder to think about complicated expressions and harder to maintain code using them.
Premature optimization is the root of all job security
| [reply] [d/l] [select] |
|
|
|
|
|
|
|
Re^2: next unless condition
by learnedbyerror (Monk) on Mar 31, 2016 at 22:15 UTC
|
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 | [reply] [d/l] [select] |
|
|
$ 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
| [reply] [d/l] |
|
|
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.
| [reply] [d/l] [select] |
|
|
I agree that you should write the clearest HLL code possible. At the local college I work with ASM students and sometimes we play "beat the compiler". With the right example, even a beginning student can do this vs the highest optimization level. This example would not be a good one because if (not $cell) ... and $cell || ... will code every similarly even with a "dumb" compiler. They are essentially the same. Load from memory, ALU operation to set flags, jump on flags that were just set. The ALU operation could be a or eax,eax(nothing but set flags) or neg eax (negate and set flags). Different kind of jump instruction required but timing is the same. I wouldn't worry about this at all. A bigger mistake in source coding is to assume that shorter source code maybe with a bunch of fancy maps, joins, and other functions is faster than longer code that is more straightforward. You can write one line in HLL that takes a lot more work at the low level that something else that takes many HLL lines.
| [reply] [d/l] [select] |
|
|
|
|
|
|
|
|
|
|
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
| [reply] [d/l] [select] |
Re^2: next unless condition
by hankcoder (Scribe) on Mar 31, 2016 at 19:04 UTC
|
Thanks Hauke D, that helps a lot.
| [reply] |