When writing a switch
statement that only ever has to deal with a known set of values (imagine an implicit enumeration), I find myself wondering what should be the last entry in the construct. I'm always considering the same 3 approaches, but I'd really like to just stick with the one that makes the most sense and never think about this again. The alternatives are described below. For the sake of discussion, let's assume there are exactly 4 options for the "switching variable".
- Approach #1: 4 cases, no
default
case. - Approach #2: 3 cases,
default
acts as the last case (+ comment explaining this). - Approach #3: 4 cases,
default
case with a "ShouldNeverHappenException
".
My thoughts on this are as follows:
- One the one hand, since
default
is effectively a case that cannot be reached, it seems pointless to clutter the code with it. - On the other hand, it's bad not to handle a
default
case out of of future-proofing considerations, that is, if someday another option becomes available (due to e.g. API changes outside of my control), the code might react to it incorrectly if thedefault
case is used for one of the expected options. - If the last case handles an error scenario, it might not be so bad if it's the default behavior (assuming I have no fine-grained error handling).
Based on the above reasoning I tend to prefer the 3rd approach, but I am no software engineer, and perhaps I'm missing something.
What are the best practices in this case?
Best Answer
I think this is the key point. Implicit means not an actual
enum
type, but, say, numbers with special meaning.And a method that is using the switch statement:
The "implicit" enumeration in this example is a 32 bit integer. The entire range of values for the 32 bit integer are your possible cases. So what if I call:
Or:
You might say "I'm always using the constants A, B and C in my program when calling this method, so it's impossible to pass -1"
But the compiler allows it, therefore a code change in the future in how DoSomething is called can pass an illegal value.
If you pass an illegal value, is there an intelligent default you can fall back on? If so, that's your
default
. If not, throw an exception.I would argue for a
default
even for an explicit enumeration:The default clause throwing an exception to the fact a value is not implemented is a good debugging tool for the future where you add an item to the enum, and then you forget to change the application behavior based on that.
Will the exception happen in production? Most likely not. It will probably happen during development or testing and be fixed.
But that's the benefit of having a default clause and either doing something by default or blowing up.
There are some cases where doing nothing is OK. I honestly would still put in a default clause with a comment:
To me this falls under the same guidelines as exception handling. If you catch the exception, do something with it. If you don't want to do anything with it, catch the exception and explain why nothing is done: