Since if/else
is similar to a switch
and often interchangeable, your confusion is understandable.
Some languages, such as Python, don't even have a switch
statement. Not surprisingly, when you Google for "python switch", the first result points to an alternative—a map. Not an if/else
, but a map.
While you can use if/else
every time instead of a switch
, you should also understand that your colleagues are not wrong when they use a switch
statement. Either they were simply told by a teacher or a mentor that they should use a switch
when there are more than two branches, or they simply find it more elegant or readable, both terms being perfectly subjective.
Your first example, by the way, annoys me a lot. If I were a reviewer of your code, I would immediately flag it, because it's easy to overlook the lack of break
statements, and so it looks like if oldVersion
is 2
, only updateToVersion3()
will be executed, but not updateToVersion4()
. Avoid writing code which is prone to errors. For instance, such syntax is forbidden in C# precisely in order to avoid mistakes which are so easily avoidable.
Your second example is a case where switch
is perfectly fine. Although I would use instead either a map (mapping functions—or even lambda expressions, and not their results) or inheritance, I would switch to switch
statement if I know that my code will be read by beginners who may not understand those two approaches.
If the style guidelines of your code base allow it, your second example may even be written this way:
switch (button){
case LEFT: moveLeft(); break;
case RIGHT: moveRight(); break;
case UP: moveUp(); break;
case DOWN: moveDown(); break;
}
or like this:
switch (button){
case LEFT: moveLeft(); break;
case RIGHT: moveRight(); break;
case UP: moveUp(); break;
case DOWN: moveDown(); break;
}
making the code shorter and more readable (again, readability is subjective) than an if/elif/else
variant.
An important aspect highlighted by J Trana is that in this second example, if/elif/else
may be error prone. I can't easily find a more illustrative example where you can migrate to switch
, but the following piece of code shows the idea. Are you able to immediately see why the following code will sometimes throw an exception at runtime (imagine it's 6 PM and you've spent three hours inspecting code)?
if (!fs.FileExists(fileFullPath)) {
debug("The file appears to be missing. Check if the location is set in the options.");
}
if (fs.ReadFile(fileFullPath).Contains(textToFind)) {
found = true;
debug("The file contains the expected text.");
}
else {
debug("The text was not found.");
}
Here again, in C#, the official style guide will prevent you from writing this error prone piece of code: it would require to add a line break before the second if
, and the author of the code will immediately see that he wrote if
instead of else if
.
That's why, in order to reduce the risk of writing code which doesn't express clearly the intentions of the author and can easily be misread:
Avoid the missing break
s in switch
statements, except in the case where the previous case
contains no logic:
switch (something)
{
case 1: // Not having a `break` is fine. The intention of the author is clear.
case 2:
hello();
break;
case 3:
world();
break;
}
Avoid else if
which may be confused with or, by mistake, replaced by, an if
, unless the style guidelines are protecting you.
Use maps and inheritance when appropriate. In most cases, maps and inheritance are more appropriate than if/elif/else
or switch
. Longer if/elif/else
or switch
tend to be a good sign that they should be replaced by a map (often) or an inheritance (rarely) or should be completely refactored (often).
The record I've seen so far is a switch
statement containing approximately a thousand case
s (written by an expert proud of his 15 years' professional experience as a lead developer).
Flatten hierarchies when possible. This code:
if (n == a) {
f1();
}
else {
if (n == b) {
f2();
}
else {
f3();
}
}
should immediately be refactored to:
if (n == a) {
f1();
}
else if (n == b) {
f2();
}
else {
f3();
}
or:
switch (n) {
case a: f1(); break;
case a: f2(); break;
default: f3();
}
Beware of insane programmers. This piece of code is equivalent to the one in the previous point, if a
, b
, c
and n
are numbers (things would be different if those were calls to functions with side effects):
if (!(n == a)) {
if (n - b == 0 && !(n > b)) {
f2();
}
}
if (!(n == a) && n - b < 0 || b - n < 0) {
f3();
}
if (n != a) {
// Do nothing.
}
else {
if (!(n > a) && ! (n < a)) {
f1();
}
}
break
(or other "jump" statement) to end a case, right?break
at the end of everycase
that makes it not OK? Your first example could be done withif
statements, too.