Never use a Switch Statement in Unity
Okay, hands up, I do not believe the title for this document but often Switch Statement can be a, “bad smell” indicating that you have missed an opportunity.
Common rationale for a Switch/Case statement
To be clear, the modern c# Switch statement is a very powerful feature. It comes with all sorts of pattern matching mechanisms that make it an extremely versatile tool. However, I am not talking about that, I am talking the oft stated claim that a Switch makes a long ‘if’ block easier to read. When I hear someone say that my internal alarm bells start to ring. Let’s take a look at a common example, collecting a power-up.
NB If you are learning C# code, then I would recommend you stop reading now. There is nothing intrinsically wrong with a Switch statement carry on using it and come back here when you have learnt more about classes and interfaces.
Collecting a power up
Consider the following code snippet;
Imagine your SpaceShip has collided with a power-up and then imagine you are okay with only using the name of the power-up (yuk), then it is pretty common to see something like the above code. (You might even see it converted to enums or string consts, but let’s not get side tracked). The argument is that this can be replaced with a switch, and code refactoring tools will help you do just that;
Hmm, it’s so much easier to read…it’s not really is it? Okay it might be a tiny bit more performant, might be…and very tiny. In fact if all I was worried about was making neat code I’d probably just write this;
That’s a lot less code than the switch, well sure you should test the dictionary first (or at least ?.Invoke()) but my point is that using a switch purely for script layout reasons seems a little suspect. But that’s not even where the code smell begins.
The Switch Code Smell
Consider we continue with the switch statement. Every time we add a new power up we extend the switch statement. But not only that but we are encouraging ourselves to embed the nature (behavior) of the power-up into the SpaceShip component. If we take a step back then that’s probably not a good idea. Does collecting an extra life affect the ship, maybe, maybe not. What is clearer is that the behaviour of each power-up should not clutter up the code for the ship. The alternative is use a more Object Orientated approach.
We encapsulate the power-up behavior in a…PowerUp class. We can then specialize the class depending upon our needs;
Each power-up can now implement its own behavior, ideally you would also change the SpaceShip to implement interfaces such as ICanChangeSpeed, ICanChangeFireRate etc, and the power-ups would look for that contract rather than SpaceShip, but that’s for another discussion.
We still need to change SpaceShip to make use of all these power-ups
Okay we seem to have written a lot more code than our humble Switch. But what we’ve done is create a better separation of responsibility. Now we are free to add lots more power-up types and we might not even need to revisit SpaceShip at all. We can just drag and drop the new power-up into the list. Okay, with this implementation you probably would need to change, but then maybe we shouldn’t be containing the fire rate in the Space Ship, or the number of lives or even the speed? This is why the Switch is a bad smell, because it encourages you to keep everything in the SpaceShip and as time goes on it will become harder to maintain…much like a real space ship…probably??
Back to life, back to reality
I come back to the fact that Switch isn’t bad, and not everything needs to have nice levels of code separation. Hopefully the take-a-ways from this article are;
- When you read that something has an advantage, be honest with yourself, re-examine if you really believe it’s true
- When you hear that “Switch’s are evil” or are asked in an interview “Why are they bad” you know that they’re not but they can encourage a poor design if you’re not careful