Dennis Myrén said:
I have to ask this question once for all;
Is there a good rule for when to use a switch statement rather than an if
statement?
I know if statements is faster in small tests,
but how many if-elseif's are considered a maximum before it is recommended
to use a switch statement?
After seeing your question, I became curious myself, so I did some tests.
I tested two scenarios, dense switches, and sparse switches. With dense
switches, we are selecting from some set of values without skipping any
values in the middle. With sparse switches, we are selecting from values
that may skip around a lot.
In all cases, the machine code generated for switch() will out-perform that
generated for if().
The machine code generated for if() ... else if() ... is a pretty faithful
translation of the source code. There are machine jump instructions for
every value tested against, and they even appear in the same order as your
source code. There are O(n) jump instructions, and it isn't affected by
whether we're doing dense or sparse tests.
The machine code generated for switch() depends on whether we do a dense or
sparse test.
The dense switch() is extremely efficient, doing pointer arithmetic to
compute the destination address of it's *single* jump instruction. This
optimization is probably only possible thanks to the special IL instruction
"switch", which the C# compiler outputs in this situation. Here, we have
O(1) jump instructions.
The sparse switch() is also very efficient, it does a series of comparisons
paired with conditional jump instructions, and only jumps one time, to the
desired case. Here, we also have O(1) jump instructions (that are actually
executed).
In addition to this, the sparse switch does all comparisons and conditional
jumps in one big stretch of machine code, which is really good for CPU
caches. The machine code for if() jumps all over the place to arrive at its
destination, so if you do a lot of work in each if(), there will be a bunch
of stuff to jump over - and therefore the locality of reference goes way
down. That translates to CPU cache misses, which are performance killers.
Another thing to consider with the dense switch() is that IL is expressive
enough to capture the compiler's intent in this situation, so the JIT for
other potential platforms may be able to optimize it even better (though
they'll have a hard time beating O(1)).
Conclusion: switch always out-performs if. That said, when there are a
small number of tests, you may choose if() just for readability if it makes
sense in a particular situation.
I only tested switch on integer types.. not strings. I suspect that
switch() would still outperform if() in this case due to locality of
reference.
Mike