Many programmers insist on only having the flow of control in their function end at a single point. I got wondering for a few minutes if any languages enforce this style of programming. Then I realized. Erlang has no 'return' operator, so doesn't Erlang enforce this? That sounds about right as far as I can see. So an Erlang function can only have 1 exit point. That should make them feel good.
Well, I think the single exit point
meme is related to
structured programming discussions and articles like Dijkstra's GOTO Statement Considered
Harmful
.
It's a quite extreme opinion with which I do not agree, at least not
without further context.
For instance, consider the following two pseudo-code snippets:
fun f1(...) do
if (...) then
r := ...
else if (...) then
r := ...
else
r := ...
end if
return ...
end fun
fun f2(...) do
if (...) then
return ...
else if (...) then
return ...
else
return ...
end if
end fun
Why is one better than the other (as postulated by the single-exit metric)?
Or, by extending this line of thought, if my language permits GOTOs I could even trivially transform every multi-exit program into a single-exit program. Why would this be better?
In contrast, having deeply nested or page-long conditionals is neither desirable. They can be avoided with multiple exits, for example (as well, or even better with refactoring, admittedly).
Another useful case of multiple exits is the simulation of contracts in a language which does not support them natively. Often, I write functions introducing data from the "outside" which look like this:
fun contract_example(...) do
if (!check1) return ... end if
if (!check2) return ... end if
...
return ...
end fun
In the context of functional programming languages, the debate usually
does not come up, mostly because programming patterns are different.
Recursion is used more often, but there a base case could be
considered the moral equivalent of an exit point
, when the
recursion is not going one level deeper:
fun contract (...) when !check1 = ...
fun contract (...) when !check2 = ...
fun contract (...) = ...
Such code is often very nice to reason about with induction because the base cases stand out, but so do they in the examples I gave above.
In fact, striving for code which is easy to reason about might be one of the causes why buzz-phrases like no GOTOs, single-exit, etc., come up, and then cause a lot of confusion.
So, I guess my (unspectacular) conclusion is that you can write reason-able code with or without multiple exits and the single-exit metric is not meaningful in itself.
I do agree that code containing exits (return, exceptions, etc.) all over the place in an unstructured way should not be written, but the emphasis here is unstructured. The reason is clearly that it is hard to assess correctness of unstructured code, and correctness should be top priority.
Related discussions:
- At Orbitz's: Single-exit point
- At Joel's: Multiple Exit Points