3 ms·
Nested ternaries are horrible. They add an additional burden to think about operator precedence, which is actually a hard thing especially if you switch between
by vast 7y ago
Nested ternaries are horrible. They add an additional burden to think about operator precedence, which is actually a hard thing especially if you switch between languages regularly. They are harder to extend for those reasons and often it is just stupid to handle condition prerequisites outside of the nesting of an if statement.
Conditional logic is the third hardest thing just after variable naming and cache invalidation. There is no excuse to make it harder to understand.
- dukoid 7y agoWell in the example in the article they are more chained than "really" nested... So I think with adequate formatting, they can reasonably replace switch/case or if/elseif expressions (in contrast to statements) for languages that don't have them...
- vitus 7y agoI always thought one of the main arguments for the guard pattern ("early exits" in the article) was _specifically_ to reduce nesting, so I find it interesting that both guard patterns and nested ternaries were mentioned. For complicated nesting that's nontrivial to simplify in this fashion, you should then think about extracting logic into helper functions. (The example is also a bit misleading, since the logic flow between the nested ifs and the chained ternaries are subtly different.) In the provided example, const result = !conditionA ? "Not A" : conditionB ? "A & B" : "A"; is really equivalent to: const result = null; if (!conditionA) { result = "Not A"; } else if (conditionB) { result = "A & B"; } else { result = "A"; } which I don't think is that bad (look ma! no nesting!). You could also use a function, especially if the logic is too complex to flatten reasonably: function checkConditions() { if (!conditionA) { return "Not A"; } // A is true from here onwards. if (!conditionB) { return "A"; } // B is also true from here onwards. return "A & B"; } const result = checkConditions();
- y4mi 7y agoYou're code example is technically nesting btw. That language doesn't have an "elseif", so you're actually writing the shorthand for if(!a) { ... } else { if(!b){ ... } else { ... } } Your point stands nonetheless. I just had to smile seeing that example
- nosianu 7y agoTypeScript documentation for conditional types advertises the use of nested conditionals: https://www.typescriptlang.org/docs/handbook/advanced-types.html#conditional-types https://www.typescriptlang.org/docs/handbook/advanced-types.... I must say that I find those examples clearly express what is going on. Also, about another poster's comment, while it may be true that for regular code needing this may be a sign that the code needs refactoring, for business logic this is not true. You may very well end up with "business logic code" where things like huge functions and long nested conditionals actually are the optimal way to express messy reality, and that trying to use refactoring methods like "put this into extra functions" actually increases complexity.
- ravenstine 7y agoIronically, it could have been written far more concisely and clearly by using IIFE, if-then statements and reordering the logic: const result = (() => { if (!conditionA) return 'Not A'; if (conditionB) return 'A & B'; return 'A'; })(); Yes, I know, I "need" to use curlies. But there's really no reason why someone shouldn't be able to quickly make sense of this. The ternary, on the other hand, is unnecessarily cryptic.
- correct_horse 7y agoCan't help but call out Rust here for it's (imo excellent) syntax. if condition {do_x()} else {do_y()} Basically there's no need for line breaks between if/else, but also they decided not to add a ternary conditional operator.
- ravenstine 7y agoif (condition) { do_x() } else { do_y() } That's the JavaScript version of what you wrote, and it's nearly identical. JavaScript doesn't require line breaks.
- kbp 7y agoThe significant difference is that in Rust, like in Lisp, `if` is an expression, so if-else essentially is the ternary operator. const x = cond1 ? a : cond2 ? b : c becomes in Rust let x = if cond1 { a } else if cond2 { b } else { c }
- tobr 7y agoWhether that’s clearer or not should be a matter of debate. I find the introduction of a function for this a potential source of confusion, when it just serves to turn statements into an expression. But it’s not an unreasonable solution. However, I’m not sure how this is supposed to be “written far more concisely”? It’s more verbose, involves more different constructs, more levels of indirection - pretty much for any definition of “conciseness“ I can think of, it is worse.