During a recent code review I was asked to put default
cases in all the files wherever switch
block is used, even if there is nothing to do in default
. That means I have to put the default
case and write nothing in it.
Is this the right thing to do?
What purpose would it serve?
3
It seems there are three cases when a default
statement is not necessary:
-
no other cases are left, because there is a limited set of values that enter the
switch case
. But this might change with time (intentionally or accidentally), and it would be good to have adefault case
if anything changes _ you could log or warn the user about a wrong value. -
you know how and where the
switch case
will be used and what values will enter it. Again, this might change and an extra-processing might be needed. -
other cases do not need any special processing. If this is the case, I think you are asked to add a
default case
, because it is an accepted coding style, and it makes your code more readable.
The first two cases are based on assumptions. So (assuming you work in not-so-small team since you have regular code reviews), you cannot afford making those assumptions. You don’t know who will be working with your code or making calls to functions/invoking methods in your code. Similarly, you might need to work with someone else’s code. Having the same coding style will make it easier to deal with someone’s (including your) code.
4
Is this the right thiong to do? What purpose would it serve ?
It’s not uncommon for company coding standards to require a default case for all switch
statements. One reason for it is that it makes it easy for readers to find the end of the switch
. Another, probably better reason is that it makes you think for a second about what your code should do when the condition doesn’t match your expectations. Regardless of the reason for the requirement, if it’s a company standard, you should follow it unless there’s an airtight reason not to.
If you believe that your switch
includes cases for every possible condition, then a good thing to do is to put an assert
statement in the default case. That way, when someone changes the code and inadvertently adds a condition that your switch
doesn’t cover, they’ll hit the assert
and realize that they need to address that part of the code.
If your switch
only covers a few of the possible conditions, but nothing special has to be done for the others, you can leave the default case empty. It’s a good idea to add a comment in that case to indicate that the default case is intentionally empty because the conditions that hit it don’t need any work to be done.
4
If you “switch” on pure enumeration type, it is dangerous to have default fallback. When you later add values to enumeration type, compiler will highlight switches with new values not covered. If you have default clause there, compiler will stay silent, and you may miss it.
7
In many respects, this question is the same as the often asked Do I need an else
clause at the end of an if
/else if
ladder that covers every option.
The answer is, syntactically speaking, no you don’t. But there is a however…
A default
clause can be there for (at least) two reasons:
- As an error handler – sure, Should never get here! is a claim that can be made, but What if it does? Data corruption, or even worse, no data validation are routes to program failure if not properly trapped. In this case, it shouldn’t be an empty clause!
- Design/Code Coverage – even in the simplest form of a flow-chart, there are two routes from an if-statement, and always an
otherwise
from a case. There is no reason whatsoever for not including these in the source code.
My philosophy is always quite simple – assess the worst case scenario of the two options, and go for the safest. In the case of an empty else
or default
clause, the worst case options are:
- Include them: An extra three or four lines of “redundant” code.
- Do Not Include Them: Rogue data or an unexpected condition is not trapped, potentially causing program failure.
Overdramatic? Maybe… but then my software has the potential of killing people if it goes wrong. I’d rather not take that risk.
As an aside, the MISRA-C guidelines {see profile for affiliation} recommend a default
clause for every switch
3
Java doesn’t force you to have a ‘default’ statement but it is good practice to have one all of the time, even if the code may never be reached (right now). Here’s a few reasons:
By having an unreachable default clause you show the reader of your code that you considered the values and know what you are doing. You also allow for future changes, say for example: a new enum value is added the switch shouldn’t silently ignore the new value; you can throw an Exception there instead or do something else.
To catch an unexpected value (in case you aren’t switching on an enum) that is passed in – it might be greater or less than what you expected, for example.
To handle ‘default’ actions – where the switches are for special behaviour. For example, a variable might be declared outside of the switch but not initialised and each case initialises it to something different. Default in this case could initialise it to a default value so the code immediately after the switch doesn’t error/throw an exception.
Even if you decide to put nothing in the default (no exceptions, logging, etc.) then even a comment to say that you’ve considered the fact default will never occur may help readability of your code; but that comes down to personal preference.
I would also add that it depends on the philosophy of the language you are using. In Erlang for example, where it is a common approach to ‘let it crash’, you would not define a default case but let your case
statement raise an error if a situation occurs that was not catered for.
You should always have a default unless you have provably and permanantly covered all cases. It costs nothing, and it’s insurance against failure to maintain your switch statement in an evolving program.
If you’re really sure you don’t care about any other cases, the default: break;//don’t care
but the default default should be something like default: throw new Error(“unexpected value”);
Likewise, you should never “drop through” a nontrivial case construct without adding a comment to the effect that you intend to drop through. Java got this one wrong at the design stage.
Consider
enum Gender
{
MALE ,
FEMALE ;
}
and
void run ( Gender g )
{
switch ( g )
{
case MALE :
// code related to males
break ;
default :
assert Gender . FEMALE . equals ( g ) ;
// code related to females
break ;
}
}
I would argue that this is superior to having a MALE case, a FEMALE case, and a default case that throws an exception.
During your testing phase, the computer will check if g is FEMALE. During production, the check will be omitted. (Yeah a microoptimization!)
More importantly, you will maintain your goal of 100% code coverage. If you wrote a default case that throws an Exception, how would you ever test it?
9