Switch … Case Considered Harmful

JavaScript 9 9 Comments

Don’t Use Switch – An excerpt from “Programming JavaScript Applications”

JavaScript has pretty normal control flow statements that use blocks delineated by curly braces. There is an exception to this: The switch ... case statement. The strange thing about switch ... case is that you must include the keyword break at the end of each case to prevent control from falling through to the next case. Fall through is a trick that allows you to let more than one case be executed. Control will fall through automatically to the next case unless you explicitly tell it not to with break. However, like the optional semicolons and curly braces, it’s possible to forget break when you really should have used it. When that happens, the bug is difficult to find because the code looks correct. For that reason, the break statement should never be left off of a case, even by design.

With that said, JavaScript has an elegant object literal syntax and first class functions, which makes it simple to create a keyed method lookup. The object you create for your method lookup is called an action object or command object, and is used in many software design patterns, including the useful and versatile command pattern.

Say you’re creating a game where the non-player fight actions are selected based on an algorithm defined elsewhere and passed in to doAction as a string. The switch ... case form looks like this:

The method lookup version looks like this:

Or, for input grouping (a frequent use case for the fall through feature): Say you’re writing a programming language parser, and you want to perform one action whenever you encounter a token that opens an object or array, and another whenever you encounter a token that closes them. Assume the following functions exist:

The switch … case form is:

The method lookup version looks like this:

At first glance, it might seem like this is more complicated syntax, but it has a few advantages:

  • It uses the standard curly-bracket blocks used everywhere else in JavaScript.
  • You never have to worry about remembering the break.
  • Method lookup is much more flexible. Using an action object allows you to alter the cases dynamically at runtime. For example, to allow dynamically loaded modules to extend cases, or even swap out some or all of the cases for modal context switching.
  • Method lookup is object-oriented by definition. With switch … case, your code is more procedural.

The last point is perhaps the most important. The switch statement is a close relative of the goto statement, which computer science giants argued for twenty years to eradicate from modern programming languages. It has the same serious drawback: Almost everywhere I’ve seen switch ... case used, I’ve seen it abused. Developers group unrelated functionality into overly-clever branching logic. In other words, switch ... case tends to encourage spaghetti code, while method lookup tends to encourage well-organized, object oriented code. It’s far too common to find implementations of switch ... case which break the principles of high cohesion and separation of concerns.

I was once a fan of switch ... case as a better alternative to if ... else, but after becoming more familiar with JavaScript, I naturally fell into using method lookup, instead. I haven’t used switch ... case in my code for several years. I don’t miss it at all.

If you ever find yourself writing a switch statement, stop and ask yourself the following questions:

  • Will you ever need to add more cases? (Queue, Stack, Plugin Architecture)
  • Would it be useful to modify the list of cases at run-time? For example, to change the list of enabled options based on context? (Mode switching)
  • Would it be useful to log the cases that get executed? For example, to create an undo / redo stack, or log user actions to your servers for analysis? (Command Manager)
  • Are you referencing your cases by incrementing numbers? E.g. case 1:, case: 2, etc… (Iterator target)
  • Are you trying to group related inputs together with the fall through feature so that they can share code?

If you answered yes to any of these questions, there is almost certainly a better implementation that doesn’t utilize switch, or its slippery fall through feature.


  1. FWIW, switch case fall thru is disabled in C#. It will give a compiler error if there is a missing break.

    I think you should say something about the performance cost. The method lookup will allocate memory and be a least a hash lookup for every call. Two hash lookups in your examples.

    Also, you’ve got some weird random question marks in the article text.

    • Eric Elliott - December 19, 2012

      Bryan,

      I decided to take a closer look at performance implications. You’re correct in stating that because of the extra check I inserted (which can be safely skipped in most cases), the version I’ve included above won’t be the fastest. However, if you omit that check, the lookup table version actually outperforms switch … case.

      http://jsperf.com/if-switch-lookup-table

      - Eric

      • Nate - May 17, 2013

        I think the reason the function lookup is faster in this scenario is because the strings are literal, and therefore when they get parsed the VM can reuse them. I made a modification to the test where each test is called with “piz”+”za” which requires that an actual string comparison is done instead of just a pointer comparison. In that scenario the switch case is faster.

        updated test

        • Eric Elliott - May 18, 2013

          Hi Nate,

          Your test is invalid because you didn’t make a change to the implementation. You made a change to the work that happens outside the implementation. You’re making assumptions about what the JavaScript interpreter is doing under the hood — something that you can’t count on staying the same, even if you have some inside knowledge of what’s currently happening. An interesting thing to note: The results I’m seeing here are radically different from the results I saw just a few months ago, even without your changes. Now I’m seeing both of Chrome’s if/else and switch…case radically outperforming the method dispatch table, while the reverse it true in Firefox.

          This just goes to show that putting too much stock in perf tests that rely on optimizations that you have no control over is a fool’s errand. When it comes to performance, you really need to focus on the issues that you as a developer have more control over. Those tend to pay off better, anyway. See “You’re Optimizing the Wrong Things.

  2. On thing to watch for when using this technique – and when using struct-y {…} objects as hashes in general – these never start off as empty containers: they inherit members from Object, such as constructor, valueOf, hasOwnProperty, and so on.

    So, for example, processToken(‘constructor’) will end up evaluating tokenActions['constructor'], which will return Object.constructor, which is indeed a function, so that will be used instead of instead of throwing an ‘Invalid Token’ error.

    You may want to consider using hasOwnProperty in addition to (or instead of) the function type check.

  3. The case against switch-statements is greatly overstated IMHO. Having used them is other languages (C,C++,C#,etc.) for many years, I am a big fan. They are: simple, efficient & clear. The fall-through “issue”/feature is rarely a problem for an experience developer. The use which requires most care occurs if you want one case to have its own code but then fall-through – this is best avoided but sometimes it may make sense in which case I recommend putting a big, fat comment explaining that program flow is intended to fall-through at this point.

    C# does things a little differently but that’s another story…

    • Eric Elliott - November 7, 2013

      I might be inclined to agree with you, but in JavaScript, we have a clearly superior alternative. So why on earth should anybody chose switch … case instead? As for your assessment that they are simple, efficient, and clear, the trigger that got me to dislike switch … case statements in the first place was not the danger of fallthrough. It was the widespread abuse of switch … case statements in real production code. I have never seen similar abuse of method lookup.




Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">