"Multi-exit considered harmful" considered harmful

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:

comments powered by Disqus