A neat way to express multi-clause if statements in C-based languages
I realized that there is a very clean way to express a multi-clause if statement by composing ternary conditional operators like this:
var result =
condition1 ? result1
: condition2 ? result2
: condition3 ? result4
…
: conditionN ? resultN
: default;
Traditionally, this would be written in a much more verbose way:
MyType result; if (condition1) result = result1; else if (condition2) result = result2; else if (condition3) result = result3; … else if (conditionN) result = resultN; else result = default;
Here is a simple real-world application of this trick:
string commentCount = n == 0 ? "no comments" : n == 1 ? "1 comment" : n < 100 ? n + " comments" : "100+ comments";
I really like this pattern because the code is very concise and clean. I am surprised that I have never seen it used anywhere.
Hugh Brown suggests an alternative way to rewrite the above code sample, which also nests conditional expressions:
string commentCount = string.Format("{0} comment%s", (n == 0 ? "no" : n < 100 ? n.ToString() : "100+"), (n == 1 ? "" : "s"));
Gotchas
Suprisingly, I don’t believe there are any major ones. The conditional operator has a very low operator precedence in C#, Java and C++. In C# and Java, only the assignment operators (=, +=, <<=, etc) have a lower precedence than the conditional. In C++, you also have to be cautious around the comma operator, but you should be using that construct rarely anyways.
If you really want to mix the switch expression with assignment operators, other conditionals, or even the C++ comma operator, use brackets to ensure that the conditional operators which are part of the switch expression will be applied last.
In all other cases, the pattern should behave as you’d expect.
Comments and Conclusion
It is great to find a neat trick in the good old C-based languages. Not only functional languages are cool.
Any thoughts? Has anyone seen this pattern before? Let me know in the comments.
Bodaniel Jeanes mentions a loosely-related trick with a switch statement. Note that this works in C, but not in C# or Java:
switch (true) { case n == 0: // do something break; case n > 2: // do something else break; default: return; }
Monday 02 Jun 2008 | Igor Ostrovsky | Uncategorized
Nice feature :). Though it’s not usable for multiline actions. Actually it’s a self-made implementation of conditional switch that is present in most functional languages
It’s certainly looks nicer than using if … else … else … etc.
Where possible. I’d really want to use a switch statement instead.
You might also want to look at Fowler’s refactoring catalog at http://www.refactoring.com/catalog/ - particularly http://www.refactoring.com/catalog/replaceConditionalWithPolymorphism.html
If you’re working on a largish system, that’s the best way to go.
This construct is less powerful than a switch statement because each branch must be a single expression. But, it is more powerful in another respect because the condition is an arbitrary boolean expression, rather than just a value to compare against.
As always, different constructs fit different scenarios. The same goes for the polymorphism solution suggested by Karl.
Personally I would stick with the if/else structure even for single line statements just to maintain code consistency (although I agree it is rather verbose).
I wonder what the performance of this would be in comparison with the regular if else usage.
Vikas: That is an interesting thought. I would not expect there to be a performance difference. The conditional operator does not evaluate both the *if* and the *else* part of the expression - only the one that it needs to. Since the compiler could conceivably translate the code from one implementation to the other, there is no unavoidable reason why one of the implementations should be faster. In practice, there may be performance differences depending on how a particular compiler happens to compile the code, though.
Igor,
It’s not necessarily less powerful than a switch statement… A tactic i’ve used before is
switch(true)
{
case n == 0:
// do something
break;
case n > 2:
// do something else
break;
default:
return;
}
However, I can’t confirm this works in *all* C-based languages. However, the ternary tactic is nice when each condition block is setting the same variable because it allows you you to perform the assignment then test for the value to assign.
Bodaniel: that is a pretty cool trick!
It does not work in C#, though. C# requires the case labels to be constants.
Still, it is clever and I like it!
hmmm….that last result could not be “100+ comments”
It’ll line up better if you move the equals sign from the assignment down to align with the colons.
This is a surprisingly common pattern. I’ve seen it often with a simple return statement:
return (n == 1) ? true : false;
Although that example is rather silly.
Or maybe:
string commentCount =
string.Format(”{0} comment{1}”,
(n == 0 ? “no”
: n
Do I have to escape my code as HTML? Okay.
Maybe this:
string commentCount =
string.Format(”{0} comment%s”,
(n == 0 ? “no”
: n < 100 ? n.ToString()
: “100+”),
(n == 1 ? “” : “s”);
or this:
string commentCount =
(n == 0 ? “no”
: n < 100 ? n.ToString()
: “100+”) +
” comment” +
(n == 1 ? “” : “s”);