I’ve gotten into several heated discussions recently (I wouldn’t call them arguments or fights as no blows were exchanged and we departed as friends) about whether an if-statement should always include a balancing else
clause in languages where it is not mandated by a ternary if form.
My feeling is a firm “no”.
Let me attempt to represent the opposing viewpoint. As far as I can tell, the “yes” faction believes that as proper diligence, an else clause should always be added to address both truth scenarios, even if the clause is populated with nothing other than a comment saying “this clause intentionally left blank”. It promotes a consistent inspection of all possible cases, on par with a switch
statement requiring full coverage.
I firmly disagree. In my opinion, if-statements boil down to three scenarios:
- Special Casing: Action that applies solely to certain logic conditions, where the absence of those conditions has no effect in the logic. In such case, I recommend to skip the
else
. There’s no point to it as the flow of execution continues past the additional steps introduced by the if-statement. Adding an else statement removes the clarity of the step-by-step logic and reduces the weight of the special casing in understanding the code. - Either-Or: Separate actions of approximately equal weight that apply to both outcomes. If statements are naturally biased towards the positive clause. If both statements are weighted the same, consider refactoring to
switch
. Even if theswitch
is ordered (as it must be in some fasion), aswitch
-statement reduces the emphasis given to either outcome. If both cases are quite large, consider breaking out functionality to dedicated methods. Further, if the logic overlaps between both cases, consider localizing the conditions closer to the differences, even if the test may be applied several times. - One case complex, one case simple: Actions that are of disparate impact or weight, where one clause greatly exceeds the complexity of the other, I always place the more complex clause first when used in an if-statement to emphasize the positive path. At the same time, if the simple case is non-trivial, this is an opportunity to consider whether the logic should be broken up or refactored in some way. If an if-clause is so significantly big that it takes up the majority of a method implementation, perhaps you should be using early return for the lighter condition and promoting the more complex logic to the main method body. To me, a heavy complex if-clause usually signifies an opportunity to refactor.
Given these styles, I don’t see any reason, whether from code-reading clarity or a strict adherence to potential future expansion, to automatically include else
-clauses as a mandatory part of a coding style. They add heaviness without real functionality and speak to a philosophy of form weighed over functionality. Code should be light, clear, and direct. Mandatory-else
is none of those things.
Am I wrong? Go ahead, convince me otherwise. I’m listening.
5 Comments
I never even considered having an ‘else’ clause a requirement.
Code needs to fit the problem it’s solving, not the programmer’s dogmas.
I think this idea is coming from the functional world, In the else clause is required in Haskell, every if must have `else` or equivalent of `else`. This has a certain mathematical purity. This is why I often use a ternary operator because it enforces handling the `else`and there is always a result of the expression. For Swift, I think It a good way of thinking of what should happen in the other case, but I don’t think you should put an empty `else {}` I think conciseness is preferred.
In the functional world, you have to have an `else` because the `if` statement is really an expression and has to return a value and the value from the `if` and the value from the `else` must also be of the same type. The `if` in Haskell is more like the ternary operator in Swift.
There is no equivalent to the Swift `if` in Haskell.
I disagree, I’ve seen lots of bugs due to not including an else case. Even further, I’ve been bitten by a missing else case in an if statement that I wrote thinking very carefully about this; 2 weeks later some other code changed and the else case was needed now. Nowadays I almost never write an if statement without the else part. When you write an if without an else, you are assuming some state that depends on previous code, and that code might change at any point. The else part ensures you are dealing with all the possible cases.
Considering that empty blocks are a poor coding practice and a hard call to code refactoring, I will have a hard time to convince you to add empty else everywhere.
Moreover, in a language like Swift where `if` is used everywhere to unwrap optional, adding `else` clauses will just cluter the code with empty `else` that just says `if the value is nil, don’t do anything with it…`, something that don’t bring any clarity.