about:drewcsillag

Musings of a programmer, musician, photographer, and Christian.

Single Return Considered Harmful

It’s funny sometimes how when you’ve done something in a particular way for long enough, it’s easy to forget why you do it the way you do. I’ve been a big fan of early return for a long time and was recently challenged on my view. The argument I had received in favor of single return was dubious to me, but it’s always good to recheck why you do something when you’ve forgotten.

So, while the title is a little hyperbolic, in most common programming languages of today, programming in a single return is decidedly worse than multiple return.

So I did some research as to the reasonings behind the recommendation of single return, and it dates back a bit to Dijkstra and before the days of structured programming, where it was the wild west of GOTO. The full recommendation is that any segment of code should have a single entry point and a single exit.

The notion of a single entry point into a segment of code is just kind of baked in these days with structured programming with objects and classes and the like. But the single vs. multiple exit thing has been contentious in the past and it even came up in comments on a previous post.

Going back to doing some research, the recommendation for single exit boils down to making sure that resources were freed upon exit of the function. If you returned early, you had to make sure you freed whatever had been allocated up until that point, files closed, etc. and if you did it all in one place, it reduced duplication, handled code evolution better and more.

So does the recommendation still hold today? In some cases yes, but in the majority of languages that are in popular use today, no. Specifically, if you’re in a language that has automatic resource management – that is languages with garbage collection, most of the argument goes away right there. But even in resource managed languages, resources sometimes still need to be dealt with explicitly. What about then? Well, if you have a language that has exceptions, then single return doesn’t even work for tracking that.

If you have exceptions, allocated resources must be managed in a try/finally, something akin to Java’s try-with-resources, or whatever the proper idiom in your language is, because anywhere an exception can be thrown is a potential exit point to your function. That is: multiple function exit points come by default.

What about garbage collected languages like Go or a language Rust where they either use multiple return values or a Result or Option? Does single return make sense there? I can give a solid “maybe”. I would say something like deferred return might be appropriate depending on the scope of the resource use within the function, that is: no returns within the scope of the resource use, but outside would be ok. For example, in pseudocode:

1
2
3
4
5
6
7
function foo():
   do something, maybe returning
   f = open(file)
   do other stuff here with no returns
   close(f)
   possibly return right after close due to things that happened inside
   do something, returning at any point in this last section

But if basically all of the function occurs with the file open, then it’s effectively single return.

For languages like C, single return is generally the right way to do things, depending on context. If the function doesn’t allocate anything that needs cleanup before function exit, e.g. it could use alloca, and it never reasonably would allocate anything that need cleanup, multiple return is just fine. That said, when using single return for resource cleanup in C, this is one of the “good and right” uses for GOTO. This way, as resources are acquired, when you wish to exit the function, you GOTO the relevant part of the cleanup code as it’s generally a first in, last out affair.

The origin for what started this whole thing for me was about readability. Unnecessary single return is generally less readable than early return. The reason being is that in order to only single return, you wind up with nested if statements where in multiple return they don’t wind up nesting. For example, the following multiple return:

1
2
3
4
5
6
7
8
9
if (foo) {
  return bar;
}

if (baz) {
  return fred;
}

return wilma;

Turns into this in single return:

1
2
3
4
5
6
7
8
9
10
11
int retVal;
if (foo) {
  retVal = bar;
} else {
  if (baz) {
    retVal = fred;
  } else {
    retVal = wilma;
  }
}
return retVal;

Now, as a general rule, I subscribe to the Zen of Python, which among other things states:

Flat is better than nested.

Single return code winds up nesting because the function has to continue on even though all the actual work is done. Making things worse is the fact that you’ve introduced an effectively useless variable, and now the reader, especially if retVal isn’t declared final, or whatever the equivalent is in the target language if it exists, has to mentally evaluate the function to make sure that retVal isn’t reassigned anywhere, which means they have to read the rest of the function, which they otherwise might not have to if they only cared about a specific case. That is: if you are reading for foo is true, in the multiple return case, you don’t have to read past return bar. In the single return, you have to scan the rest of the method to see what, if anything, happens to retVal. In the case where nothing happens to retVal save for the final return, you’ve now wasted your reader’s time looking for something that’s not even there.

So if you’re in a resource managed language that has exceptions (e.g. Java, Python, Ruby, Javascript, clojure, Haskell, Scala, Erlang, et. al.) single return buys you exactly nothing. Declare the actual intent of your code, return early when that’s what it’s effectively doing. Don’t make your reader have to evaluate the code when they don’t have to.

If you’re in a language without exceptions, by all means, single return as you require.