DEV Community

Ben Halpern
Ben Halpern Subscriber

Posted on

I've never become overly convinced that switch statements are that much cleaner than `if else if else if else if else`

I sort of know that switch statements are typically considered a good idea when chaining together a lot of else if statements. I'm not against this refactor in any big way, but I've also never found it overly important.

I tend to find the behavior and syntax of if and else to be pretty consistent regardless of language compared with switch statements so reaching for if is easier, but even when chained doesn't seem that much less clean than switches.

I definitely agree that getting rid of if..else..else chains are worth refactoring away, but I haven't found that a switch statement actually improves the quality meaningfully.

Thoughts?

Oldest comments (81)

Collapse
 
theringleman profile image
Sam Ringleman • Edited

Considering it rapidly speeds up your conditional statements, I will always use a switch statement. A switch statement acts as though you are accessing an array via an index. Whereas an elseif statement has to process each conditional statement until it passes.

Collapse
 
theringleman profile image
Sam Ringleman

Of course this depends on the context of the application though. If I am checking against static values, then my previous statement is true.

Collapse
 
andrewharpin profile image
Andrew Harpin

Depends on if scripted Vs compiled.

A compiler will optimise into either the conditions or a jump table depending on the code. Usually for both switch and if else

Collapse
 
theringleman profile image
Sam Ringleman

As someone who has never had the chance to jump into a compiled language, this is wonderful information! Thank you for the correction.

Collapse
 
wincentbalin profile image
Wincent Balin

AFAIK the compilers for embedded systems translate the switch-statements to jump tables, hence we might perceive this construct as an abstraction for a certain low-level structure(s).

Of course, looking from the developer's perspective only it is just an oversized if..else if..else-statement with indentation problems.

Collapse
 
taillogs profile image
Ryland G

In terms of performance, it never practically matters. For sake of the argument, switch is much faster if you have a large number of cases and slightly slower with small number of cases. The compiler is aware of the number of cases and will convert the switch statement into a constant lookup time hash table once it exceeds a threshold. But once again, for 99.999% of code, the difference between the two will never be meaningful.

I personally think that they are used differently, and that using them both is actually the best option. If/Else can be used very broadly, but with switch it's pretty niche. It's essentially a jump table that's useful when you have a ton of outcomes given some input. When I see a switch, I immediately know the class of problem it's trying to solve. With if/else, it could be much broader.

Collapse
 
andrewharpin profile image
Andrew Harpin

A good optimiser will use the optimal output for the size of the operation, irrelevant of the code statement.

Collapse
 
taillogs profile image
Ryland G

I'm sorry but this is a really uneducated comment.

Collapse
 
yaser profile image
Yaser Al-Najjar • Edited

That's why we never have switch in Python 😁

And, the dictionary is always a better and cleaner alternative for the ugly switch.

def my_switcher(x):
    return {
        'a': 1,
        'b': 2,
    }[x]


print(my_switcher('a'))
print(my_switcher('b'))
Enter fullscreen mode Exit fullscreen mode
Collapse
 
therenegadecoder profile image
Jeremy Grifski

Whenever I think about why I don't like a certain way a language does something, I realize it always goes back to my love for Python. That language has ruined me. haha

Collapse
 
yaser profile image
Yaser Al-Najjar

❤ for the utmost ruining lang.

Collapse
 
lysofdev profile image
Esteban Hernández

How would you handle a default case in this?

My though is to add || defaultValue at the end since a failure to match any property will return undefined. Thoughts?

Collapse
 
yaser profile image
Yaser Al-Najjar • Edited

That would be handy using a try except:

def my_switcher(x):
    switches = {
        'a': 1,
        'b': 2,
    }
    default = 3

    try:
        result = switches[x]
    except KeyError:
        result = default

    return result



print(my_switcher('a'))
print(my_switcher('b'))
print(my_switcher('c'))

I added the extra default variable just to make the code self explanatory.

EDIT: Bad solution, look at the other comments.

Thread Thread
 
rhymes profile image
rhymes

You can also use defaultdict in the standard library :D

Thread Thread
 
pedromendes96 profile image
Pedro Mendes • Edited

This is clean :D

Thread Thread
 
lysofdev profile image
Esteban Hernández

This is the answer to this entire thread.

Thread Thread
 
yaser profile image
Yaser Al-Najjar

@rhymes and @pedromendes96 got it better than me 😁

Collapse
 
kylegalbraith profile image
Kyle Galbraith

Really love this pattern. I have seen various approaches to the default case that vary across languages.

Collapse
 
gidrek profile image
Giovanni Cortés • Edited

Elixir :)

def my_switcher("a"), do: 1
def my_switcher("b"), do: 2
def my_switcher(), do: 3

iex(1)> Example.my_switcher("a")
1
iex(2)> Example.my_switcher("b")
2
iex(3)> Example.my_switcher()
3
Enter fullscreen mode Exit fullscreen mode
Collapse
 
kip13 profile image
kip

Pattern matching to the rescue ?

Thread Thread
 
cescquintero profile image
Francisco Quintero 🇨🇴

Isn't this feature called method overloading ? 🤔

Thread Thread
 
gidrek profile image
Giovanni Cortés

No, because overloading is have same parameters with different types, but in patter matching you can have the same type and number of parameters but differs in the content. For example, here!

Collapse
 
seanwash profile image
Sean Washington

I quite like cond as well for certain situations as well.

Collapse
 
kspeakman profile image
Kasey Speakman • Edited

The main detractor with if statements is that you have to reduce your logic down to booleans, which can later be hard to trace through. But, switch statements do not go far enough to help the situation either. Reducing your logic down to integers or strings is not that much better of an abstraction. Both force you to reduce the expressiveness of your solution down to a primitive level.

This is a reason I am a big fan of Union types, which allow you to explicitly model your logically different cases along with their different related data. Combined with pattern matching, you can branch off those logical cases as-is. My favorite language which supports this is F#.

Collapse
 
cubiclebuddha profile image
Cubicle Buddha

Kasey, I have a question for you since I’m interested in F#. I use union types all of the time in TypeScript, but I often “unpack” (for a lack of a better word) the union by using an if statement. It’s really convenient since TypeScript has excellent control flow analysis and therefore discriminates the union so you know that it is only the one type.

So do you still prefer the functional approach for discriminating the union even in languages that can clarify the resulting type?

(I’m sorry if this question isn’t more clear. I suppose I’m suggesting that if statements are fine since I think the left/right monad thing very confusing)

Collapse
 
kspeakman profile image
Kasey Speakman

Typescript union types are a bit different from those in F#. There is a tradeoff made between them. Union declarations are more or less anonymous in Typescript, whereas F# requires you to create a Discriminated Union with explicit tags. So, the Typescript feels a little nicer on declaration. However, when you unpack the union type, I believe F# has the advantage. Using match you can get auto-completion of the cases and warning when all cases are not exhaustively matched. It also provides access to the value as the appropriate type.

Examples:

// TypeScript
function padLeft(value: string, padding: string | number) {
    if (typeof padding === "number") {
        return Array(padding + 1).join(" ") + value;
    }
    if (typeof padding === "string") {
        return padding + value;
    }
}

// usage
let foo = padLeft("padded", 4);
// "    padded"
let bar = padLeft("padded", "bar ");
// "bar padded"
Enter fullscreen mode Exit fullscreen mode
// F#
type Padding =
    | Text of string
    | Spaces of int

let padLeft padding str =
    match padding with
    | Text prefix ->
        prefix + str
    | Spaces count ->
        String.replicate count " " + str

// usage
let foo = padLeft (Spaces 4) "padded"
// "    padded"
let bar = padLeft (Text "bar ") "padded"
// "bar padded"
Enter fullscreen mode Exit fullscreen mode

So, I feel like the latter is a better expression of intent in the long run. Even though it requires an extra type declaration, the type declaration adds some value for readability. It is more clear what the code is going to do with "string | number" when labeled as Text and Spaces.

For F#, I also swapped the order of arguments so that padLeft would be chainable with other string functions using pipe (|>).

Thread Thread
 
cubiclebuddha profile image
Cubicle Buddha

What a wonderful response. Thank you for being generous with your time to write that thoughtful response. You should post that as it’s own article so more people can benefit from it. :)

Collapse
 
anwar_nairi profile image
Anwar

I am not a big fan, it forces me to use break a lot... Good old if... else never failed me so I am being faithful 😁

Collapse
 
nepeckman profile image
nepeckman

For me its about using the semantics of the language to communicate as much information as possible to other developers (and my future self). Its the same reason I prefer map, filter, reduce over for loops. By using switch instead of else if, I communicate a more specific action is taking place: dispatch over a single value. It's a small thing, but its also easy to do and makes my code a little more compact, so why not?

Collapse
 
therenegadecoder profile image
Jeremy Grifski • Edited

Personally, I oppose switch statements because they force you to opt-in to break rather than breaking by default (i.e. use continue for fallthrough). I feel like every time I write a switch statement I forget a break on one of the cases. Then, I'm stuck exposing that fallthrough case during testing. In contrast, you don't really get that same ambiguity with if/else if/else.

Collapse
 
steelwolf180 profile image
Max Ong Zong Bao

I'll pick if statements over switch in a heartbeat. Never missed it when I'm programming in Python daily at work.

Collapse
 
bvmcode profile image
bvmcode

All redux reducers just gasped