DEV Community

A Case Against Switches

Jonathan Kuhl on November 11, 2018

The Problem Switches are ugly. They are bug prone. The default fallthrough behavior is begging for errors. I think Swift did the righ...
Collapse
 
darkain profile image
Vincent Milum Jr

I can understand this from a JavaScript perspective, but this technique is very language specific. One of the HUGE reasons why switch statements exist in the first place is due to the way C/C++ compilers can optimize them behind the scenes. They're significantly faster to process if done correctly, because the compiler will build a jump table rather than a series of comparisons. In modern programming where we're just basically doing glue layers and performance isn't as critical, it doesn't matter much, but when you're working with microcontrollers or doing hardware drivers, it makes a world of difference.

Another advantage of switch statements is that some languages will allow for backwards comparisons. You can do something like "switch (true)" and then run a ton of cases to see which one is true first, and then process accordingly.

Collapse
 
jckuhl profile image
Jonathan Kuhl

Sure, if the language you're working in has a lot of optimization for switches, then go with what works best for the language. My post was indeed mostly centered around JS. I know little about C++, so I won't presume to speak on it. If switches are better in C/C++, stick with them.

And even in JavaScript, if the situation is such that a switch is the simplest and most efficient way to achieve what you're looking for, then I'd remain with the structure.

Collapse
 
codevault profile image
Sergiu Mureşan

Switches, as you said, are an ugly and poorly implemented concept. This object to switch trick is fairly useful in cases you need lots of cases to check for.

Call me crazy but, most of the time, I simply use a long else if chain when needing a switch. It feels natural, it's much more readable than the object one and it works in any language.

All in all, very useful post!

Collapse
 
darkain profile image
Vincent Milum Jr

Some language implementations have a limit to the number of "else if" statements you're allowed to use though.

Collapse
 
codevault profile image
Sergiu Mureşan

Interesting. I never knew that. What languages have this limitation?

Thread Thread
 
darkain profile image
Vincent Milum Jr

It isn't language specific, it is implemention specific. I know some C/C++ compilers have this issue, but not all.

Thread Thread
 
codevault profile image
Sergiu Mureşan

For embedded I can see that limitation and that switch could look much more readable since you're mostly working with numbers (integers, addresses etc.) instead of more complex structures (objects, strings etc.)

Collapse
 
aodev profile image
AoDev • Edited

With your example it works because values are non empty strings.
But since you are explaining a pattern here, it must be said that the check for default value is actually buggy.

Any falsy value will lead to the default "branch" because using "if" like this will check the value at key "x" and not if the key exists, unlike switch that actually matches against case.

You should be checking if the key is defined instead.
An example could be:

return choices.hasOwnProperty(x) ? choices[x] : choices.default
Collapse
 
jckuhl profile image
Jonathan Kuhl

That's a good point.

Collapse
 
miguelpinero profile image
Miguel Piñero • Edited

Maybe you can do something like this:

return choices[x] || choices.default
Collapse
 
aodev profile image
AoDev

This would not work. I have explained why above.

Collapse
 
joelnet profile image
JavaScript Joel

I totally agree. Another cool option is to use Ramda's cond.

var fn = R.cond([
  [R.equals(0),   R.always('water freezes at 0°C')],
  [R.equals(100), R.always('water boils at 100°C')],
  [R.T,           temp => 'nothing special happens at ' + temp + '°C']
]);
fn(0); //=> 'water freezes at 0°C'
fn(50); //=> 'nothing special happens at 50°C'
fn(100); //=> 'water boils at 100°C'
Collapse
 
erebos-manannan profile image
Erebos Manannán

If you want something like that, it really seems much less "magical" to simply use a class + methods.

Even in old JS this seems clearer:

function spellbook() {
}

spellbook.prototype = {
  fireball: function() {
    return 'Wizard casts Fireball!'
  },
  iceshard: function() {
    return 'Wizard casts Ice Shard!'
  },
  arcanemissiles: function() {
    return 'Wizard casts Arcane Missiles'
  },
  polymorph: function() {
    return 'Wizard casts Polymorph!'
  },
  default: function() {
    return 'Wizard doesn\'t know that spell.'
  }
}

var spells = new spellbook()
var spell = 'fireball'
if (!spells[spell]) {
  spell = "default"
}
console.log(spells[spell]())
Collapse
 
g4vroche profile image
Hugues Charleux • Edited

An other point in favor of objects instead of switches, is that they are composables: we can spread the declaration of a big object through multiple files for a better code organisation.
It's a great pattern for example to keep Redux reducers gathered by domain / feature

Collapse
 
martinhaeusler profile image
Martin Häusler

You're barking up the wrong tree here. In day-to-day JavaScript practice (at least in my experience) there is very little actual object orientation involved. The frameworks do the OO stuff, "client" code is mostly object literals and JSON. Hardly anything has a prototype other than "object". And switch statements are all over the place. I don't agree with this style of programming, I'm with you on replacing switches with polymorphism. But I'm afraid the JS world won't listen.

Collapse
 
zayelion profile image
Jamezs Gladney

Good idea, I love purity, but when looking for a bug with a debugger it doesnt stop on the code and does not make the error very clear. So I keep cases in and put demand for break in the linter.