What a redundant else is
An else is redundant when the if branch before it always ends the function with return. Once a return runs, nothing after it in that function executes, so the code that follows the if can only be reached when the condition was false. Wrapping that code in an else says the same thing a second time.
Here is the function from the exercise. It returns n when n is negative and -n otherwise, so its result is never positive:
class Solution {
func negative(_ n: Int) -> Int {
if n < 0 {
return n
} else {
return -n
}
}
}
It returns the right values. Only the shape of the code can be improved.
Why the else can go
Follow the two paths through the method:
- When
n < 0, the first branch runsreturn n. The method is over, so nothing below theifblock is executed. - When
n < 0is false, the program skips theifblock and continues with the next line below it.
The second path is the same one the else described. Whatever sits in the else block can therefore move out and follow the if, with the same behaviour for every input.
The exercise, step by step
- Check that the
ifbranch returns. It does:return nis its only statement. - Delete the
elsekeyword and its braces. Theifkeeps its own closing}. Removing theelseremoves one pair of braces. - Keep the
return -nline and move it one level out, so that it sits directly below theifblock with the same indentation as theif.
class Solution {
func negative(_ n: Int) -> Int {
if n < 0 {
return n
}
return -n
}
}
The results are unchanged: negative(-4) still gives -4, and both negative(4) and negative(0) still give their non-positive values, -4 and 0.
Why it is better
- Less nesting. The final line sits at the method's top level, not inside a second block. In longer functions, this keeps the main path of the code in one straight column.
- The special case comes first. A reader sees the exceptional condition handled and dismissed at the top, and the rest of the method describes the normal case.
- Fewer lines and fewer braces to read and to keep matched.
The pattern scales to several cases. Each early return removes one possibility, and nothing needs an else:
func grade(_ score: Int) -> String {
if score >= 90 { return "A" }
if score >= 80 { return "B" }
return "C"
}
Here grade(95) returns "A", grade(85) returns "B" and grade(10) returns "C".
When the else must stay
- The
ifbranch doesn't always return. If it only prints, execution carries on after the block, so removing theelsewould run the following code in both cases. With a function whoseifbranch runsprint("x")and has noreturn, the linereturn -nbelow the block would run regardless of the condition. - Both branches are equally important. Some code reads better when the two outcomes sit side by side, and keeping the
elsethen costs nothing.
The compiler also keeps you honest. In Swift a function with a return type needs a return on every path. After the cleanup, the method still ends with a return, so it compiles. If you delete the final line by mistake, you get missing return in instance method expected to return 'Int'.
Key takeaways
- If an
ifbranch always returns, theelsearound the remaining code is redundant. - Remove the
elseand its braces, and keep the code below theifat the same indentation level. - The behaviour stays identical; the code gets flatter and easier to read.
