Making “switch” Cool Again: Go Reinvents the Extremely Useless Syntax

The switch statement is seldom used in most applications, but appears in almost all programming languages. I believe this is because switchis only useful in a very specific case. Thankfully, Go took a step back and said “we don’t have to do it the way everyone is used to” and rethought what it means to handle lots of branches of the same decision point without resulting to a chain of ifstatements.
The “break” Killed the “switch”
Consider the simplest and most obvious use of a switch
in C++. Most languages that implement switchwill use a similar syntax:
int dayOfTheWeek = 3;
char *dayName = null;switch (dayOfTheWeek) {
case 1:
dayName = "Monday";
break;
case 2:
dayName = "Tuesday";
break;
case 3:
dayName = "Wednesday";
break;
case 4:
dayName = "Thursday";
break;
case 5:
dayName = "Friday";
break;
case 6:
dayName = "Saturday";
break;
case 7:
dayName = "Sunday";
break;
}
I realise this could be reduced to an array; just pretend these are more random values if you wish. This is already long and cumbersome, however it is slightly neater but longer than the alternative with chained if else
statements:
int dayOfTheWeek = 3;
char *dayName = null;if (dayOfTheWeek == 1) {
dayName = "Monday";
} else if (dayOfTheWeek == 2) {
dayName = "Tuesday";
} else if (dayOfTheWeek == 3) {
dayName = "Wednesday";
} else if (dayOfTheWeek == 4) {
dayName = "Thursday";
} else if (dayOfTheWeek == 5) {
dayName = "Friday";
} else if (dayOfTheWeek == 6) {
dayName = "Saturday";
} else if (dayOfTheWeek == 7) {
dayName = "Sunday";
}
To me this is very ugly, repeats a lot of code and is less explicit than the switch
version, but since it’s shorter and more flexible it’s usually the preferred option. Now let’s see how Go handles it:
dayOfTheWeek := 3
var dayName stringswitch dayOfTheWeek {
case 1:
dayName = "Monday"
case 2:
dayName = "Tuesday"
case 3:
dayName = "Wednesday"
case 4:
dayName = "Thursday"
case 5:
dayName = "Friday"
case 6:
dayName = "Saturday"
case 7:
dayName = "Sunday"
}
Yes! Now we get to the crux of it. The breakstatement is the wart that has killed the beautiful simplicity of the switch. It should have been original designed with the intention that in the vast majority of cases you will only want one case to match and not have to pollute your source with breakstatements.
Collapsing Cases
Since the normal implementation relies on the breakto not fall through; several cases can grouped. Go takes it one step further by comma separating all the matching values. This is less typing and even more explicit:
dayOfTheWeek := 3
var dayName stringswitch dayOfTheWeek {
case 1, 2, 3, 4, 5:
dayName = "Weekday"
case 6, 7:
dayName = "Weekend"
}
Expressions
The other reason why switchis seldom used is because in many languages the value that it’s switching on must by a primitive, sometimes even restricted to an integer. Go removed this limitation as well by allowing complete expressions for cases:
switch {
case dayOfTheWeek <= 5:
dayName = "Weekday"
case dayOfTheWeek > 5:
dayName = "Weekend"
}
If you use expressions for cases you do not need to even specify a switch value. This works more like a chained ifstatement. Furthermore, Go’s ability to declare scoped variables makes this switch even more readable:
dayOfTheWeek := 3
var dayName stringswitch friday := 5; true {
case dayOfTheWeek <= friday:
dayName = "Weekday"
case dayOfTheWeek > friday:
dayName = "Weekend"
}
Empty Cases
Empty cases mean it does nothing:
switch hasHadCoffee {
case false:
// Don't talk to me.
case true:
readyToTalk()
}
Falling Through
If traditional switches rely on break
statements to not fall through, then fallthrough
would be the opposite. A casenever falls through unless you have an explicit fallthrough:
count := 0switch {
default:
count++
fallthrough
case false:
count++
}
It’s important to recognise that countis 2
because fallthroughwill always run the next case, even if it wouldn’t normally be hit.
Type Switching
One great thing about Go is that type casting and assertions can be put into the same line:
var value interface{} = "hello"
if str, ok := value.(string); ok {
// str must be a string
} else {
// error handling
}
If there are more than one possible expected type you can do the same thing with a switch:
var value interface{} = "hello"
switch o := value.(type) {
case string:
// o is a string
case int:
// o is an int
default:
// Handle the unknown type
panic(o)
}
Conclusion
Go not only makes switch
useful, it reinvigorates and promotes it to a powerful and flexible tool. I believe similar functionality could be implemented in other languages by using functions and arrays… Maybe a side project there.
Originally published at http://elliot.land on February 27, 2016.