

Why switch is better than if-else
source link: https://mortoray.com/2019/06/29/why-switch-is-better-than-if-else/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.


Why switch is better than if-else
In Ben’s post, he questions whether switch statements are cleaner than if-else chains. I contend they are, because they better express the semantics of the code, allow less room for errors, reduce duplication, and potentially improve performance.
Better Semantics
Switch statements express a different meaning than a chain of if-else statements. A switch indicates that you are mapping from an input value to a piece of code.
switch( expr ) { case value_0: ... case value_1: ... }
It’s clear at a glance that we’re attempting to cover all possible values of expr
. Somebody reading this code can quickly determine what is supposed to be happening.
This is not as clear with the equivalent if-else chain:
if( expr == value_0) { ... } else if( expr == value_1) { ... }
We aren’t certain here whether we mean to cover all possible values, or only these values in particular.
Many compilers will inform you when a switch
statement is missing a condition. In C++ this could be a missing case
statement for an enumeration. In Rust, the equivalent match
construct covers an even wider range of input, and also disallows missing coverage. This automatic checking by the compiler can prevent common defects. For example, if you add a new value to an enumeration, the compiler can tell you all the locations where you haven’t covered that new case.
Less room for errors and nonsense
One problem of an if-else chain is that it allows any comparison, with any variable. Having no restriction on the form increases the ability to hide errors.
if( expr == value_0 ) { ... } else if( expr == value_1 ) { ... } else if( expr2 == value_2 ) { ... } else if( value_3 == expr ) { ... }
Why is there an expr2
in there? It’s now unclear whether the code intends to cover all values for expr
or the conditions are only coincidentally similar.
What about the reversed order of value_3 == expr
? This should be corrected in code review, but it’s another possibility of creating confusion.
Refactoring can create this type of problem. An individual may modify the expressions, either fixing an error, or cleaning it up. In a parallel branch another programmer adds a new expression. During merge the two different code forms will come together, resulting in an inconsistent form.
Reduced duplication
Long chains of if-else have unnecessary syntax overhead. Redundancy is one of the principle evils of source code. From the previous example with expr2
, we saw that the repeated typing of an expression can’t be ignored. You can’t glance at an if-else chain and assume it’s functioning like a switch, since it may not be. The redundancy adds cognitive load when reading the code.
The duplication could have a performance impact, as well as creating another avenue for errors. I’ve used only expr
so far, but what if that expression were a function call?
if( next_obj().get_status() == state_ready ) { ... } else if( next_obj().get_status() == state_pending ) { ... } else { ... }
The first potential error here is the call to next_obj
. If the first condition is true, it will evaluate once. If the first condition is false, the next if statement makes another call to the function. Does it return the same value each time, or is it incrementing over a list?
What about get_status()
? Is this a cheap or expensive function to call? Maybe it slowly calculates or invokes a database call? Calling it twice doubles whatever the cost is, which may be significant in many cases.
It’s important to store these values in a temporary to avoid both of these problems. This is unfortunately something a lot of coders forget to do, as they quickly copy-paste the first if-else, and then repeat.
state = next_obj().get_status() if( state == state_ready ) { ... } else if( state == state_pending ) { ... } else { ... }
You could avoid the problem using a switch
statement, which only evaluates the expression once.
Better performance
In many cases a switch statement will perform better than an if-else chain. The strict structure makes it easy for an optimizer to reduce the number of comparisons that are made.
This is done by creating a binary tree of the potential options. If your switch statement contains eight cases, only three comparisons are needed to find the right case.
switch( c ) { case 0: ... case 1: ... case 2: ... case 3: ... case 4: ... case 5: ... case 6: ... case 7: ... }
An optimizing compiler, or intelligent runtime, can reduce this to a binary search of the numbers.
if( c <4 ) { if( c < 2 ) { if( c == 0 ) { //0 } else { //1 } } else { if( c == 3 ) { // 3 } else { // 4 } } } else { //repeated for 4...7 }
A clever optimizer might recognize an if-else series the same way. But the potential for minor variations in the statements reduces this possibility. For example, a function call, hidden assignment, or use of an alternate variable, would all prevent this optimization.
By using a semantically significant high-level form, you give the optimizer more options to improve your code.
Language problems
Switch statements aren’t without their problems, however. In particular, the C and C++ form that requires an explicit break
statement is problematic. Though, it also allows multiple cases to be packed together.
I like Python a lot, though am upset that it doesn’t have a switch statement. While maps and function dispatching cover several cases, it does not cover all of them.
Rust has a much better match
statement. It retains the high-level semantics of a switch statement, but adds a lot better pattern matching. Though I’m not a fan of the language, I think it has the best version of a switch statement. I should call it pattern matching, which in language design, is the more general name for these feature. You’ll see in other languages like Haskell as well.
Perhaps that’s the biggest problem with switch
. It feels like a stunted version of proper pattern matching. But that’s no reason to abandon it entirely and go back to if-else. Switch statements produce cleaner code as they express semantics, avoid duplication, and reduce the chance of errors.
Related
Recommend
-
40
在很多时候,我们代码中会有很多分支,而且分支下面的代码又有一些复杂的逻辑,相信很多人都喜欢用 if-else/switch-case 去实现。做的不好的会直接把实现的代码放在 if-else/switch-case 的分支之下: switch ( type )
-
13
Why case classes are better than variant types Dec 2, 2011 One of the better features from functional programming languages are variant types (a.k.a. algebraic data types). Basically they are a way of enumerat...
-
4
Who else is tired of waiting for a much better Apple TV? A remote that can be found...
-
9
Responses (46)
-
10
Practical Programming AdviceRemove Your If-Else and Switch CasesHow to double the amount of code for the better.
-
8
This site can’t be reached anything.else.other.than.vi’s server IP address could not be found. ...
-
5
I don't know if you've ever encountered an if-else nesting like a pyramid placed horizontally: if (true) { } if (true) { } if (true) { if (true) { if (true) { } } else { } }...
-
6
Does anyone else feel like the M1 MBA is now an even better deal?
-
10
How to Help Someone Else Spend Time Better (Yes, It Is Possible)We all know someone who really struggles with time. Perhaps this person can’t figure out what to spend time on, so things get done at the last...
-
6
Why Do Americans Own More Guns Per Capita Than Anyone Else? One question for Jennifer Carlson, a sociologist at the University of...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK