Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is exiting a function with an empty return statement good/bad practice?

I've seen many examples and this is getting me more than curious

The two examples are the following :

  • Having return;at the end of a void function, this is flat out ridiculous.
  • Using return;in the middle of a function to break out of it. I don't like it.

The following example might clarify the second case (the first one being obvious):

- SomeMethodThatReturnsSomethingOrNot(var param1){

    if (param1 == null){

         CallThisMethod();
         return;
    }

    CallThisOtherMethod(param1);

}

To a lot of people, this is fine and clear. To me, it is acceptable at best.

Why not simply using an if else? You avoid the need to return nothing in the middle of the code, it doesn't decrease readability, and, well, I don't know what else to say, it just looks like a better practice to me.

- SomeMethodThatReturnsSomethingOrNot(var param1){

        if (param1 == null){
             CallThisMethod();
        }else{
             CallThisOtherMethod(param1);
        }

    }

Now I'd like to emphasize the simplicity of the example here, I know somethign sexier could be made but lets just pretend its something a bit more complex than a null check, that requires the same kind of if-returninsteadof if-else technique.

So, what are everyone's thoughts?

I've been strongly against returning something when the method is either void, or when I don't actually want to return anything. If I end up in that situation, I like to rethink my architecture because it shouldn't happen.

Am I completely wrong/right or is there some discussing space here?

like image 990
Gil Sand Avatar asked Oct 24 '25 18:10

Gil Sand


1 Answers

You might be interested in looking into the subject of SESE (single entry, single exit) and Dijkstra's thoughts on the subject which kind of prompted this style.

It's worth noting though that Dijkstra's thoughts are often misunderstood. He was advocating practices during an era where a lot of people were writing code in straight assembly. In assembly, you're often allowed to jump from any instruction to any other. That's where the notion of "single-entry" comes from: it's extremely confusing to jump from one function into the middle of another.

"Single-exit" is often misinterpreted to mean exiting a function from only one place. It actually meant exiting a function to only one place. It becomes extremely confusing if you returned out of a function to a place other than the site in which it was called.

Nevertheless, a lot people today continue to think of "single-exit" to mean, "exit from only one place in a function", and advocates often promote the style you're suggesting.

I won't go into which one is better or worse. It's inevitably going to be subjective. But there are some things worth thinking about.

Explicit Cleanup

The idea of exiting from only one place in a function was largely popularized during eras that required explicit cleanup in many functions with respect to their resources -- something like this:

function f()
    allocate_resources()
    ...
    deallocate_resources()
end

We can see if we introduced any kind of early return statement in such a function that we could easily forget to deallocate the resources and end up with some kind of resource leak. In these cases, the suggestion to favor return statements only at the end of a function become significantly more useful to prevent human errors.

Exception-Handling

Exception-handling is now a common feature in many modern languages. With exception-handling, there can be implicit exits all over a function. Example:

function f()
    list = create_list()   -- could throw
    list.insert(123)       -- could throw
    connect_to_server()    -- could throw
    if x == 0 then
         add_some_widget() -- could throw
    end
end

In these cases, any line of code could have an implicit exit point from the function as a result of an exception being thrown. As a result, it's impossible to make the control flow totally predictable. There too, comes an inevitable need for automated resource management where it's up to the compiler (or garbage collector) to clean up resources automatically, not up to the developer to do it manually, because it becomes too impractical to do it manually with so many implicit exit points in a function.

Conclusion

So these are some of the considerations to make. I'm personally in the middle-lower end of the spectrum (if "low" means putting returns anywhere, and "high" means only at the bottom). But it's all up to you where you find your comfort zone, and what kind of code you find easiest to understand and maintain.

In my humble opinion we could go cross-eyed trying to analyze the merits of exactly how a function is written down to every single line of code, but I'd have to appeal to a pragmatic sort of view of like just test it well, make sure the interface and documentation is clear, make sure the implementation maybe passes a basic litmus test of not causing people's brains to explode, and then ship it.