Assigning a value depending on conditions
tl;dr
string database =
isAdmin ? "masterDB" :
(stature > 100) ? "regionalDB" :
(name=="Johnny") ? "dummyDB" :
"userDB";
If-then-else is awful
Let's say you want to assign some values to a variable. A common pattern would look like:
string myVariable = "";
if(isAdmin) {
myVariable = "masterDB";
} else if(stature > 100) {
myVariable = "regionalDB";
} else {
myVariable = "userDB";
}
This solution has three flaws as I see it:
- It is verbose and bulky. With lots of keywords, newlines and brackets. Also the variable name and assignment operator is repeated.
- You might forget the else-clause, potentially resulting in a null pointer exception.
- It branches your logical flow into different code paths, and invites dangerous behaviour like adding other statements inside the blocks.
Now, setting the default value at the first line migitates (1) and (2) by allowing you to remove the last else-clause:
string myVariable = "userDB";
if(isAdmin) {
myVariable = "masterDB";
} else if(stature > 100) {
myVariable = "regionalDB";
}
I would however argue that this is worse. The first line now reads: I want to set myVariable to "userDB". Without seeing the other lines, it is no longer obvious that this is the fallback-value. We have introduced complexity (albeit on a minor scale).
Switch-case is even worse
Look at the complaints about if-then-else. Switch solves almost none of these. The only thing switch is good for is not repeating the conditions, if the different conditions are just comparing the same value.
string myVariable = "";
switch(niceConditionVariable) {
case "a":
myVariable = "masterDB";
break;
case "b":
myVariable = "regionalDB";
break;
default:
myVariable = "userDB";
}
The downside?
- More keyword bloat: case, break, and default.
- You might forget a break-statement, causing a fall-through to the next statement. (Yes, the C#-compiler will warn against this in some cases. Still, what happens in other environments? Java?)
- The syntax is odd in a world that abandoned gotos and labels some twenty years ago!?
Nested ternaries
A common way to structure ternaries is to try indenting them like they were if-then-else statements:
string myVariable = (isAdmin)
? "masterDB"
: (stature > 100)
? "regionalDB"
: (name == "johnny")
? "dummyDB"
: "userDB";
This is quite horrible for readability. Notice how the resulting values are horizontally aligned with another condition than its own!
I would suggest to format it like this instead:
string myVariable =
(isAdmin) ? "masterDB" :
(stature > 100) ? "regionalDB" :
(name == "johnny") ? "dummyDB" :
"userDB";
- It is immediately clear what the statement is supposed to do: assign a variable depending on some conditions.
- It can not perform other operations in the branches (unlike the other patterns).
- It reads pretty much like a pattern matching, or configuration. If the left, then the right.
- It is impossible to forget the fallback value, and it is placed last (as is proper).
Are there downsides? Yes, especially in non compiled languages (like JavaScript). The ternary operator has quite high priority, causing some headaches if you forget parentheses:
string suffix = "DB";
string myVariable =
(isAdmin) ? "master" + suffix : // oops
// ....
(isAdmin) ? ("master" + suffix) : // ok
All in all, I really like the intent shown by using ternaries. "In this statement I want to assign a variable, and nothing else."