A Case Against Switches
Tags: javascript
Published: 2018-11-11 01:31:22

---
title: A Case Against Switches
published: true
description: Switches are ugly, avoid them.
tags: javascript
---

## The Problem

Switches are ugly.  They are bug prone.  The default fallthrough behavior is begging for errors.  I think Swift did the right thing and made `fallthrough` a keyword, rather than a default, but even then, I'd rather avoid them if I can.  They just don't fit in with the rest of my code.  The indentation is awkward and no one can seem to decide if the case statements are indented or not.

Python didn't even bother to implement them in the language.

I primarily work in JavaScript, so I'll be focusing on that language.  However, any language with first class functions and some sort of key/value pair structure can avoid switches.  Java, for example, can use maps and lambdas.  But I'll be sticking with JavaScript.

## The JavaScript Object

How do we avoid switches?  Well, each case in a switch is essentially a key-value pair.  You're matching a single key, the case, with a single value, an expression to be evaluated, or a set of instructions.  Sound familiar?  Boil it down to two key works, *key* and *value* and you have a basic JavaScript object.  How do we use a JavaScript object in place of a switch?

Well let's start with an example.  Let's pretend we have some code that displays an error message when a log in fails.

```javascript
errorMessage(error) {
    const status = {
        '401': 'Please check your username and password',
        '404': 'Account not found, have you registered?',
        '500': 'Something went wrong with the server, please try again later',
        'Failed to fetch': 'Servers are currently down, please try again later'
    }
    return status[error.status];
}
```

Here we have code that behaves like a switch.  We have 4 different error messages that can get thrown, a 401 if verification fails, a 404 if the user isn't found, a 500 if something broke, or a `Failed to fetch` if the server is down.  All we have to do is a very basic look up on an object and that's it.  No fall through, no jarring `switch` structure.  Just a basic JavaScript object.

But what if I wanted a default case?  Well that's simple too, we just need to check if the value is in the object itself.  There are a number of ways to do this, but I'll just check if the property exists by checking for `undefined`:

```javascript
errorMessage(error) {
    const status = {
        '401': 'Please check your username and password',
        '404': 'Account not found, have you registered?',
        '500': 'Something went wrong with the server, please try again later',
        'Failed to fetch': 'Servers are currently down, please try again later',
        default: 'Something borked, sorry!'
    }
    if(!status[error.status]) {
        return status['default'];
    }
    return status[error.status];
}
```

Current JavaScript is also fairly flexible.  If I wanted to use numbers rather than strings for object keys, I can do that.  JavaScript will, under the hood, turn them into strings.  Therefore the following is also valid JavaScript:

```javascript
const object = {
    1: 'one',
    2: 'two',
    3: 'three'
}

object[1]; // 'one'
```

Of course, you can't use dot notation on this object, `object.1` is invalid, but if we're simply using this object as a switch, then it doesn't matter.  With bracket notation, dot notation isn't mandatory anyways.  But what's important here is that we can recreate switch behavior with both strings and numbers.  Now you _could_ use `true` and `false` as strings for keys if you wanted to make a boolean, but I argue a switch is overkill for a boolean anyways.

## Functions?

However, when we're using `switch`, we're often doing more than grabbing strings and numbers, we might also be holding functions.  Thankfully, JavaScript is a language that treats functions as first class citizens.  Functions can be passed around like any other object, and of course, can be the values of properties in our objects.

Here arrow functions truly shine, though if you need to preserve `this`, you'll have to reach for `Function.prototype.bind()`, or use the old school syntax for JavaScript anonymous functions,`function () { ...`.  Function shorthand in JavaScript objects also preserve the context of `this` and in that case, the name of the function, becomes the key, and the instruction block becomes its value.

```javascript
const greet = {
    sayHello1: function() { return 'Hello' },
    sayHello2() { return 'Hello' },
    sayHello3: ()=> { 'Hello' }
}
```
In this example, `greet.sayHello1()` and `greet.sayHello2()` do exactly the same thing.  `greet.sayHello3()` is slightly different because it is an arrow function and therefore the `this` keyword is lost.  However since the function isn't using `this`, all three are exactly the same in this particular scenario.  If you needed `this` for an arrow function, you can do `greet.sayHello3.bind(greet)`.

Imagine we have a text based RPG.  You play a wizard who has a number of spells he can cast.  The user types in the spell he wants and the wizard casts it.  You could use a switch to determine which spell to cast, or use an object:

```javascript
function castSpell(spellname) {
    const spellbook = {
        fireball: ()=> 'Wizard casts Fireball!',
        iceshard: ()=> 'Wizard casts Ice Shard!',
        arcanemissiles: ()=> 'Wizard casts Arcane Missiles',
        polymorph: ()=> 'Wizard casts Polymorph!',
        default: ()=> 'Wizard doesn\'t know that spell.'
    }
    if(!spellbook[spellname]) {
        return spellbook['default']();
    }
    return spellbook[spellname]();
}
```

So what the function does is, you pass in a spell name, and it uses the spellname to match a value in the spellbook.  That value is a function, so by using `()` after grabbing the value will call that function.

> I'm using bracket notation for the default method here for consistency.  `spellbook.default()` would also be valid.

Here we can call functions the same way we would in a switch.  You can abstract away all the code that would be your case statements and shove them in an object methods and simply call them via bracket notation.

This does have some trade offs, as it's harder to tell what `spellbook[spellname]()` is doing than `case 'fireball': return fireball();` but the code is more elegant, there are fewer levels of indentation, and no threat of fallthrough.

## But I Want Fallthrough!

Oh.  Well then.  Obtaining fallthrough behavior in an object is more difficult and there's no one way to do it.  There could be an argument here where `switch` might actually be a better construct to use.  And if so, then use `switch`.  But understanding that objects have a number methods on them, there are other solutions as well.  With `Object.values()`, `Object.keys()` and `Object.entries()`, you can get all of your key/value pairs into arrays and then run them through any number of array functions.  This can be done to achieve fallthrough.

Imagine we have an object with a bunch of functions and, given a number, we need to call all the functions upto, and not including that number.  This is one case where a switch fallback is useful, but this is also easily done with an object.  Here's an example:

```javascript
function callFns(number) {
    const object = {
        1: ()=> console.log('one'),
        2: ()=> console.log('two'),
        3: ()=> console.log('three'),
        4: ()=> console.log('four'),
        5: ()=> console.log('five')
    }

    Object.keys(object).forEach(key => {
        if(key >= number) {
            object[key]();
        }
    });
}
```

Call `callFns(3)` and it will log `'three'`, `'four'`, and `'five'` to the console.  This would simulate using `switch(3) {` with no `break` or `return` in any cases.  By combining Object and Array methods, we can simulate a fallthrough for our situation.  But again, this may be a case where a `switch` might be the better construct.  After all, the primary cause of bugs in a switch _is_ the fallthrough feature.  However, by using an Object, you get access to a number of methods that can make an object more flexible than a switch statement.  By getting an array of your object's entries, you get access to `filter`, `reduce`, `some`, `every`, as well as iteration methods like `map` and `forEach`, and structures like `for of`.

## In Summary

Objects in JavaScript give you a simple alternative to the `switch` statement.  Objects are flexible and less bug prone than `switch` statements and they aren't as jarring in your code as switch statements.  If you don't want fallthrough, using an object in place of a switch is a better option.  If you do want fallthrough, it can be achieved through Object and Array methods, but a regular `switch` might be a better option.

All in all, your style of code is up to you, but I suggest being like Python and throwing the switch out entirely.

Happy Coding.