5 ms·
Just a reminder that in most compiled and JIT optimized languages with switches, this switch (c) { case 4: return 30; case 5: return 70; default:
by vortico 7y ago
Just a reminder that in most compiled and JIT optimized languages with switches, this
switch (c) {
case 4: return 30;
case 5: return 70;
default: return 0;
}
compiles to the same instructions and therefore same performance as
if (c == 4) {
return 30;
}
else if (c == 5) {
return 70;
}
else {
return 0;
}
As a side note, it's easier to see accidental fallthroughs if you write switch statements like this.
switch (c) {
case 4: {
return 30;
} break;
case 5: {
return 70;
} break;
default: {
return 0;
} break;
But in my opinion, the `if` statement is more clear in both cases, and only one level of indentation instead of 2.
- enriquto 7y agoAre you sure? I'd guess that if the cases are an interval of consecutive integers it may do a "jmp [c]" sometime.
- vortico 7y agoLooks the same to me. https://godbolt.org/z/CfhD5k https://godbolt.org/z/CfhD5k Switches were invented mostly because they were an easy hint to the compiler to reduce to a tree search, but because compilers are smart today, they're obsolete unless you just prefer their syntax. Even if the cases are consecutive, most compiler optimizers are smart enough to determine that the ASTs are equivalent.
- enriquto 7y ago> they're obsolete unless you just prefer their syntax. This is a good point. Sometimes I prefer the (ugly) syntax of switches than that of conditionals. The reason is that a chain of conditionals is non-symmetrical (there's no condition for the first "case"), while a switch is formally invariant to permutation of the cases. I have even seen shit like this: if (false) ; else if (c == 1) { first case ; } else if (c == 2) { second case; } ... just to preserve the symmetry along the cases.
- vortico 7y agoAre you talking about the `else` being non-symmetric? You don't need it at all. I do this. if (c == 1) { first case ; } if (c == 2) { second case; }
- KMag 7y agoYou're correct. Many compilers will emit jump tables if the domain is dense enough. Also, even if compiling to a bunch of conditional jumps, they'll usually emit them to require O(log N) conditional jumps (equivalent to a binary tree of nested ifs) instead of the O(N) linear arrangement suggested by the GP.
- vortico 7y agoClang compiles both switch statements and `if` statements to the same tree search code. E.g. https://godbolt.org/z/7M_3PU https://godbolt.org/z/7M_3PU My point is that the optimizations you're describing for switch statements are also applied to a bunch of `if` blocks, at least in LLVM-based languages with an LLVM version from the last several years.
- KMag 7y agoSure, I didn't mean to imply that compilers never (or commonly didn't) detect that long if-chains could be optimized to jump tables, lookup tables, or if-trees. I was just answering the more narrow question the GGP was asking: if switch statements were always lowered to if-chains and never compiled to jump tables.
- vortico 7y agoAh I see, gotcha.
- bla3 7y agoThat's only true if there are <= 3 "clusters" of switch case values, else compilers do smarter things. See https://youtu.be/gMqSinyL8uk https://youtu.be/gMqSinyL8uk
- vortico 7y agoIs this what you mean by more clusters? Looks like clang compiles the two functions to roughly the same "tree search" code. https://godbolt.org/z/7M_3PU https://godbolt.org/z/7M_3PU
- comex 7y agoHuh. To my eyes, the switch version is "obviously" much more clear! It's significantly more compact, with less visual noise you have to mentally ignore. And having the possible inputs and outputs lined up vertically (especially with nothing else between them) makes it easy to understand the logic. Plus, using a switch indicates at a glance that the variable being tested is the same in all cases, whereas with an if-else-if chain there could be any weird expression hiding in one of the conditions. Eye of the beholder, indeed.
- vortico 7y agoPerhaps a better comparison to the switch statement is if (c == 4) return 30; if (c == 5) return 70; return 0;
- comex 7y agoYep, that's a big improvement in my eyes, making it comparable from a readability perspective. In my opinion, that leaves more minor pros and cons of each approach, depending on the language. For example, in C and C++, as kazinator mentioned elsewhere in the thread, GCC and Clang now have an option to require all fallthroughs to be explicitly annotated, which effectively removes one of the main downsides of switch. And switch is better at detecting duplicate cases, as well as checking for exhaustivity if you're matching against enum variants. On the other hand, if you change the example so that the cases don't return (perhaps they assign to a variable instead), with switch you would need to add a `break;` after each one, increasing visual noise. If statements don't have that problem. Or if you change the example so that one of the values `c` is compared to is not a constant, some languages (C, C++, Java but not JavaScript, PHP) don't allow that with switch statements...