Re: Ternary if versus normal if question
by blokhead (Monsignor) on Nov 17, 2005 at 13:24 UTC
|
Run the code with -MO=Deparse,-p, and the line with the ternary operator becomes:
(($lights{$light} ? ($lights{$light} = 0) : $lights{$light}) = 1);
You can see that the 2nd assignment operator has lower precedence than the ternary operator. So this says,
If $lights{$light} is true, then assign 1 to the result of "$lights{$light}=0", otherwise assign 1 to the result of $lights{$light}.
... which is not what you want. A better way to use the ternary here is:
$lights{$light} = $lights{$light} ? 0 : 1;
Or even better still is probably:
$lights{$light} = ! $lights{$light};
which toggles $lights{$light} between true & false.
| [reply] [d/l] [select] |
|
|
| [reply] [d/l] [select] |
Re: Ternary if versus normal if question
by wfsp (Abbot) on Nov 17, 2005 at 13:23 UTC
|
$lights{$light} ? $lights{$light} = 0 : $lights{$light} = 1;
to:
$lights{$light} = $lights{$light} ? 0 : 1;
it works ok.
From perlop:
If the argument before the ? is true, the argument before the : is returned, otherwise the argument after the : is returned.
update:
Added quote from the docs
| [reply] [d/l] [select] |
Re: Ternary if versus normal if question
by blazar (Canon) on Nov 17, 2005 at 14:03 UTC
|
I expect the following code to behave the same whether using "normal" if or "ternary" ? : ; style if.
You seem to be confused. C<?:> is an operator, whereas if is a flow control syntactical keyword. While you can use the former instead of the latter:
(.5<rand) ? print "Wow\n" : die "horribly";
you really shouldn't. I may get heavily downvoted for saying that you "can", so I'll stress once more that you really really shouldn't. Except in golf and obfu, that is.
The point is that you should use C<?:> if you're interested in its return value. And of course you can't use if instead of it, because the latter does not return anything. You will rapidly learn in which situations it is worth to use one and in which ones it is worth to use the other... | [reply] [d/l] [select] |
|
|
Thanks very much to you and all those who clarified the ternary if to me. However, what is meant by the C in C<?:>? Is that shorthand for some concept?
| [reply] [d/l] |
|
|
It's the pod format of Perl documentation. Apart that, it is also used in ASCII contexts to visually mark code, but I generally avoid it here since whe have <code> tags anyway. In this situation, however, it seemed to me to be too be too short and confusing, so I added that pseudo-markup.
| [reply] [d/l] |
|
|
(.5<rand) or die "horribly";
is acceptable. In fact even encouraged. Can you explain to OP and others why your very compact and easily read example is so much worse than:
if (.5<rand) {
print "Wow\n";
} else {
die "horribly";
}
Granted, were the string in either case much bigger, or were more lines of code required than shown in either case, if starts to look much better. Even better however would be the or die idiom.
However, this doesn't really apply to OP's context where $var = <cond> ? <case 1> : <case 2>; is ok and $var = ! $var; is much better.
DWIM is Perl's answer to Gödel
| [reply] [d/l] [select] |
|
|
Why shouldn't you? Perl idiom says that:
(.5<rand) or die "horribly";
is acceptable. In fact even encouraged. Can you explain to OP and others why your very compact and easily read example is so much worse than:
It is worse in that short circuiting or used in contexts like the one you're referring to makes for very clear syntax imitating its use in natural languages. Indeed the practical rule of a thumb is to use low-precedence logical operators for flow control and high-precedence ones to operate on values. Of course there are reasonable situations in which it is reasonable to violate this "rule", but in most cases it does apply.
if (.5<rand) {
print "Wow\n";
} else {
die "horribly";
}
To be fair I happen rarely enough to (have to) use a full if ... then ... else construct like the above. In this case, for example
die "horribly" if .5 < rand;
print "Wow\n";
would suffice. Of course this is specific of the particular example under examination, but I make a frequent use of blocks (sometimes also for loops having the sole purpose of aliasing to $_) and of last, next, and more rarely redo and they make for quite as compact but still perfectly readable syntax.
| [reply] [d/l] [select] |
Re: Ternary if versus normal if question
by Moron (Curate) on Nov 17, 2005 at 14:29 UTC
|
And yet, why not $lights[$light] = !$lights[$light];
| [reply] [d/l] |
|
|
Or, more succinctly, $lights[$light] ^= 1;.
| [reply] [d/l] |
|
|
Beware of strings vs numbers, though. The bitwise ops in Perl are hazardous if used imprudently.
Makeshifts last the longest.
| [reply] |
|
|
I looked for a solution with ^=, but it doesn't work unless it can be made into a unary operator at which point I gave up looking down that route. Your suggestion only turns the light on when off but does not turn it off when on.
| [reply] |
|
|
|
|