Reputation: 53331
I went looking through Raphael.js
's source code to find out how he converted RGB values to HSB. I found out the function he did it in and I was in the process of converting it to Python when I bumped into this nice triple-nested ternary operator:
H = (C == 0 ? null :
V == r ? (g - b) / C :
V == g ? (b - r) / C + 2 :
(r - g) / C + 4
);
It threw me for a loop because Python doesn't have the same kind of ternary operator that Javascript does. I spent a while looking over it and eventually hashed this somewhat saner code (using only if/else) out of it:
if (C == 0) {
H = null;
} else {
if(V == r) {
H = (g - b) / C;
} else {
if(V == g) {
H = (b - r) / C + 2;
} else {
H = (r - g) / C + 4;
}
}
}
Was my interpretation correct? I'm only asking this because if it isn't correct, I'm faced with a lot of debugging. So. Did I "get it"?
Upvotes: 63
Views: 135562
Reputation: 1
I tend to avoid nested if/else (even more nested ternary operators ? :
) statements as I find them hard to understand when I'm reading code.
One way to avoid nesting is to use early returns on functions. To do this we use a lambda.
const H = (() =>
if(C == 0) {
return null;
}
if(V == r) {
return (g - b) / C;
}
if(V == g){
return (b - r) / C + 2;
}
return (r - g) / C + 4;
)();
Upvotes: 0
Reputation: 23873
To my personal taste, a carefully aligned nested ternary beats the if-else mess:
const H =
C == 0 ? null :
V == r ? (g - b) / C :
V == g ? (b - r) / C + 2 :
(r - g) / C + 4 ;
Upvotes: 55
Reputation: 58
Why not use ternary operators found in Python?
H = (
None if C == 0 else
(g - b) / C if V == r else
(b - r) / C + 2 if V == g else
(r - g) / C + 4
)
Upvotes: 0
Reputation: 4522
As mentioned in MDN Docs:
function example(…) {
return condition1 ? value1
: condition2 ? value2
: condition3 ? value3
: value4;
}
// Equivalent to:
function example(…) {
if (condition1) { return value1; }
else if (condition2) { return value2; }
else if (condition3) { return value3; }
else { return value4; }
}
Upvotes: 3
Reputation: 4105
If your JavaScript codebase contains nested ternary statements like the one in question, consider converting the formatting to daisy chained ternary statements instead.
H = (C == 0) // Is C zero?
? null // Then return `null`, else ...
: (V == r) // Is V equal to r?
? (g - b) / C // Then return this value, else ...
: (V == g) // Is V equal to g?
? (b - r) / C + 2 // Then return this value
: (r - g) / C + 4; // Otherwise fall back to this default value
They simply read top to bottom in a straight line, returning a value as soon as they hit a truthy condition or the fallback.
–Nested Ternaries are Great, Eric Elliot
Upvotes: 12
Reputation: 4178
Here's another, more elegant idea...
if (C != 0)
{
if (V == r) return (g - b) / C;
if (V == g) return (b - r) / C + 2;
return (r - g) / C + 4;
}
return null;
Just wrap this in function and use instead of H...
Upvotes: 1
Reputation: 759
H = C == 0
? null
: V == r
? (g - b) / C
: V == g
? (b - r) / C + 2
: (r - g) / C + 4
I've seen Dan Abramov using this indentation placement pattern. While I don't like how the conditional operator ?
no longer visually follows the condition, I prefer this to something like @lolmaus's example in that the indentation will always be consistent regardless the size of the conditional.
You actually start to look at it as ?
true :
false which is visually intuitive here. And this way, I find the ternary is much easier to spot and differentiate from the surrounding code.
Upvotes: 7
Reputation: 664969
Yes, it's right (apart from capitalisation differences). Yet, it may be cleaner written without any parentheses, readable as elseif:
if (C == 0)
h = null;
else if (V == r)
h = (g - b) / C;
else if (V == g)
h = (b - r) / C + 2;
else
h = (r - g) / C + 4;
Upvotes: 3
Reputation: 236114
The same logic can be written in a simpler way:
var H
if (C == 0)
H = null;
else if (V == r)
H = (g - b) / C;
else if (V == g)
H = (b - r) / C + 2;
else
H = (r - g) / C + 4;
It's possible to omit the curly braces because there's a single statement in each condition. And given that the conditions are mutually exclusive, using else if
is much clearer than nesting if
s.
Upvotes: 6
Reputation: 119867
I think you can have this to avoid the deep nesting:
var H
if(C == 0){
H = null;
}
else if(V == r){
H = (g - b) / C;
}
else if (V == g){
H = (b - r) / C + 2;
}
else {
H = (r - g) / C + 4;
}
Upvotes: 42