Most optimizing compilers will emit a jump table for a switch, which is a good way to get a reasonably high performance interpreter while keeping the code pretty clean. The performance is better than using virtual methods [1].
Most optimizing compilers will emit a jump table for a switch, which is a good way to get a reasonably high performance interpreter while keeping the code pretty clean. The performance is better than using virtual methods [1].
For example, look at Python's ceval.c, which has a switch table implementation and the text "The traditional bytecode evaluation loop uses a "switch" statement, which decent compilers will optimize as a single indirect branch instruction combined with a lookup table of jump addresses."
Actually, it also has a version which uses GCC's "Labels as Values" extension, see http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html . The comment then points out that this non-portable solution is up to 15-20% faster than a large switch statement, because having N jump points instead of 1 improves the CPU's branch prediction.
As haberman says, this is "actually good code", not "justifiable" bad code.
I am another who dislikes the term "code smell." I agree with mbrock - I would rather get a comment which reflects the underlying complaint than use a proxy term like "code smell". In your reply to mbrock you wrote:
> the "smell" is just a heuristic that says that without any additional arguments in its favor, a hundred-case switch usually isn't the cleanest and most maintainable way to implement something.
Why not just say "a hundred-case switch statement usually isn't ...", and omit a reference to "smell"? What additional meaning does the term "code smell" lend?
I dislike using the term "code smell" in general. Some people detest stinky cheeses, or a peaty whisky, while others adore the complex aromas. Often this is a learned taste which comes with age and experience.
As a result, the obvious rebuke to any "this is a code smell" comment is "that's because you aren't mature enough to appreciate it." I can't think of any effective response which stays on topic, other than to bring the conversation back to the specific problems in the code. Why not just start from that point instead?
For example, I wrote a very small JIT compiler for Brainfuck. It uses switch() to do code generation. It's extremely clean and elegant code, if I do say so myself. Breaking apart the switch() with some kind of OO approach would make the program longer and less clear: http://blog.reverberate.org/2012/12/hello-jit-world-joy-of-s...
Do you look at that and think "this doesn't look good" just because it uses switch()? If so, your heuristic could use a little tuning.
But now let's talk performance. In interpreter/VM main loops, bytecode dispatch is a huge factor in the overall performance of a VM. This issue isn't "theoretical," "minor," or "premature," it's the result of extensive measurement and experimentation by many people over a large amount of time. If you are not familiar with this well-studied issue, here is some recommended reading:
http://software.intel.com/en-us/forums/topic/298506
http://lua-users.org/lists/lua-l/2011-02/msg00742.html
http://www.cs.tcd.ie/publications/tech-reports/reports.07/TC... (see section 3.3)
It is not a bad pattern to have switch in those cases, but it is often present in code analyse rules. Code analyse tools are very bad to distinguish between good use of a feature that is rarely used and missuse of this feature.
If you create code that smells, you should justify it (in comments or other documentation). Likewise just saying it smells without suggesting an alternative is unhelpful to the discussion.
Can you contextualise the criteria? Can you match those criteria to this context?
(Not rhetorical, I'd like to know the answer.)