Early returns are easy to read because although return is a staunchly imperative construct (a form of "go to"), early returns are structured such that they simulate a multi-case conditional from a functional language.
You know that each early return completely handles its respective case; if that branch is taken, that's it; the function has ended. There is only way to reach the code past the if/return, which is that the condition has to fail.
The conditionals inside a function that has a single return are harder to read, because no conditional is necessarily final.
if/elses that all return can be readable:
if (this) {
if (that) {
return x;
} else {
return y;
}
} else {
return z;
}
still, it can be flattened:
if (!this)
return z;
if (that)
return x;
return y;
It's shorter and less nested, and so that's a readability improvement. It's not as easy to see that
x is returned when both
this and
that hold. The intermediate version below helps with that:
if (this) {
if (that)
return x;
return y;
}
return z;
If the conditions are cheaply tested variables, or simple expressions easily optimized by the compiler, there is also:
if (this && that)
return x;
if (this)
return y;
return z;