One of my side-projects at the moment involves me porting an old-ish (20+ years) large-ish (100,000+ lines of code) network game server from C to Go.
Thanks to cgo, similarities between C and Go, and the power of (some horrific) Vim regular expressions and macros, this is less epic than it might initially sound!
However, one thing has repeatedly stood out in the process, and will inevitably have me tearing my hair out in future due to the subtle bugs I’ve introduced as a result…
Here is a short C program with a switch statement:
And here is a short Go program with a switch statement:
If you’re familiar with only one of the two languages, or just casually glancing, you might assume they had the same output. They do not.
Here is the output of the C code:
And of the Go:
In C, switch statements are basically “jump to the first matching case statement, keep executing until you hit a break or the end of the switch block” (which allows some “interesting” techniques like Duff’s Device and this coroutine implementation).
So in the C example, when
execution “jumps to” the
case 1, continues into
case 2, prints
Foo, and then hits the
break and leaves the
case blocks are more like entities in their own right - “if the conditions of this block match, execute the block”.
So in the Go example, when
case 1 block is executed, it’s empty so nothing happens, and that’s it.
A common error in C is to forget to put a
break at the end of a case block and then have multiple cases execute.
Go avoids this by treating the blocks as self-contained units, which I see as much more intuitive and better.
What Go currently (1.11) doesn’t do is warn on unnecessary
breaks at the end of a block,
as one might have if trying to write Go with the C model in mind.
Both behaviours are reasonable, both are fine once you get them, but when you’re switching back and forth between the two languages, good luck making sure you don’t fall into this trap!