114

I've always heard about a single exit-point function as a bad way to code because you lose readability and efficiency. I've never heard anybody argue the other side.

I thought this had something to do with CS but this question was shot down at cstheory stackexchange.

hex bob-omb
  • 1,149
  • 2
  • 8
  • 3
  • 3
    possible duplicate of [Any research on maintainability of "guard statement" vs. "single function exit point" paradigm available?](http://stackoverflow.com/questions/2292702/any-research-on-maintainability-of-guard-statement-vs-single-function-exit-po), or maybe [Are multiple return points from a method good or bad?](http://stackoverflow.com/questions/137115/are-multiple-return-points-from-a-method-good-or-bad), or [Should a function have only one return statement?](http://stackoverflow.com/questions/36707/should-a-function-have-only-one-return-statement) – finnw Jan 29 '11 at 19:05
  • 9
    The answer is that there is no answer that is always right. I often find it easier to code w/multiple exits. I've also found (when updating the code above) that modifying/extending the code was more difficult due to those same multiple exits. Making these case-by-case decisions is what our job is. When a decision always has a "best" answer, there's no need for us. – JS. Jan 13 '12 at 23:10
  • 2
    @finnw the fascist mods have removed the last two questions, to make sure they will have to be answered again, and again, and again – Maarten Bodewes Feb 19 '12 at 15:06
  • In spite of the word "argue" in the question, I really don't think this is an opinion-based question. It's quite relevant to good design, etc. I see no reason for it to be closed, but w/e. – Ungeheuer Nov 21 '16 at 17:21
  • 5
    A single exit point simplifies debugging, reading, performance measuring and tuning, refactoring, This is objective and materially significant. Using early returns (after simple argument checks) makes for a sensible blend of both styles. Given the benefits of a single exit point, littering your code with return values is simply evidence of a lazy, sloppy, careless programmer -- and at least possibly not liking puppies. – Rick O'Shea Sep 19 '17 at 23:45
  • With a single exit point you can add **post conditions** at the end of a function just before it returns. With multiple exit points you would have to duplicate them for each return statement. – August Karlstrom Mar 13 '23 at 13:03

8 Answers8

126

There are different schools of thought, and it largely comes down to personal preference.

One is that it is less confusing if there is only a single exit point - you have a single path through the method and you know where to look for the exit. On the minus side if you use indentation to represent nesting, your code ends up massively indented to the right, and it becomes very difficult to follow all the nested scopes.

Another is that you can check preconditions and exit early at the start of a method, so that you know in the body of the method that certain conditions are true, without the entire body of the method being indented 5 miles off to the right. This usually minimises the number of scopes you have to worry about, which makes code much easier to follow.

A third is that you can exit anywhere you please. This used to be more confusing in the old days, but now that we have syntax-colouring editors and compilers that detect unreachable code, it's a lot easier to deal with.

I'm squarely in the middle camp. Enforcing a single exit point is a pointless or even counterproductive restriction IMHO, while exiting at random all over a method can sometimes lead to messy difficult to follow logic, where it becomes difficult to see if a given bit of code will or won't be executed. But "gating" your method makes it possible to significantly simplify the body of the method.

Jason Williams
  • 56,972
  • 11
  • 108
  • 137
  • 2
    Deep nesting may be obviated in the ``singe exit`` paradigm by dint of ``go to`` statements. In addition, one gets the opportunity to perform some postprocessing under the function's local ``Error`` label, which is impossible with multiple ``return``s. – Anton Shepelev Oct 07 '15 at 14:03
  • 2
    There is usually a good solution that avoids the need for a go to. I much prefer to 'return(Fail(...))' and put the shared cleanup code into the Fail method. This may require passing a few locals in to allow memory to be freed etc, but unless you're in a performance critical bit of code this is usually a much cleaner solution than a goto IMO. It also allows several methods to share similar cleanup code too. – Jason Williams Oct 07 '15 at 15:48
  • There is an optimal approach based on objective criteria but we can agree there are schools of thought (correct and incorrect) and it does come down to personal preference (a preference for or against a correct approach). – Rick O'Shea Sep 19 '17 at 23:27
44

My general recommendation is that return statements should, when practical, either be located before the first code that has any side-effects, or after the last code that has any side-effects. I would consider something like:

  if (!argument)  // Check if non-null
    return ERR_NULL_ARGUMENT;
  ... process non-null argument
  if (ok)
    return 0;
  else
    return ERR_NOT_OK;

clearer than:

  int return_value;
  if (argument) // Non-null
  {
    .. process non-null argument
    .. set result appropriately
  }
  else
    result = ERR_NULL_ARGUMENT;
  return result;

If a certain condition should prevent a function from doing anything, I prefer to early-return out of the function at a spot above the point where the function would do anything. Once the function has undertaken actions with side-effects, though, I prefer to return from the bottom, to make clear that all side-effects must be dealt with.

Community
  • 1
  • 1
supercat
  • 77,689
  • 9
  • 166
  • 211
  • Your first example, managing the `ok` variable, looks as the single-return approach to me. Moreover, the if-else block can be simply rewritten to: `return ok ? 0 : ERR_NOT_OK;` – Melebius Nov 07 '16 at 11:24
  • 2
    The first example has a `return` at the start before all the code which does everything. As for using the `?:` operator, writing it out on separate lines makes it easier on many IDEs to attach a debug breakpoint to the not-ok scenario. BTW, the *real* key to "single exit point" lies in understanding that what matters is that for each particular call to a normal function, the exit point is *the point immediately after the call*. Programmers nowadays take that for granted, but things were not always thus. In some rare cases code may have to get by without stack space, leading to functions... – supercat Nov 07 '16 at 19:42
  • ...which exit via conditional or computed gotos. Generally anything with enough resources to be programmed in anything other than assembly language will be able to support a stack, but I've written assembly code that had to operate under some very tight constraints (down to ZERO bytes of RAM in one case), and having multiple exit points can be helpful in such cases. – supercat Nov 07 '16 at 19:48
  • 3
    The socalled clearer example is much less clear and hard to read. One exit point is always easier to read, easier to maintain, easier to debug. – GuidoG Nov 16 '16 at 11:45
  • 9
    @GuidoG: Either pattern might be more readable, depending upon what appears in the omitted sections. Using "return x;" makes it clear that if the statement is reached, the return value will be x. Using "result = x;" leaves open the possibility that something else might change the result before it's returned. That can be useful if it in fact would become necessary to change the result, but programmers examining the code would have to inspect it to see how the result might change even if the answer is "it can't". – supercat Nov 16 '16 at 16:26
19

With most anything, it comes down to the needs of the deliverable. In "the old days", spaghetti code with multiple return points invited memory leaks, since coders that preferred that method typically did not clean up well. There were also issues with some compilers "losing" the reference to the return variable as the stack was popped during the return, in the case of returning from a nested scope. The more general problem was one of re-entrant code, which attempts to have the calling state of a function be exactly the same as its return state. Mutators of oop violated this and the concept was shelved.

There are deliverables, most notably kernels, which need the speed that multiple exit points provide. These environments normally have their own memory and process management, so the risk of a leak is minimized.

Personally, I like to have a single point of exit, since I often use it to insert a breakpoint on the return statement and perform a code inspect of how the code determined that solution. I could just go to the entrance and step through, which I do with extensively nested and recursive solutions. As a code reviewer, multiple returns in a function requires a much deeper analysis - so if you're doing it to speed up the implementation, you're robbing Peter to save Paul. More time will be required in code reviews, invalidating the presumption of efficient implementation.

-- 2 cents

Please see this doc for more details: NISTIR 5459

sscheider
  • 522
  • 5
  • 14
18

Single entry and exit point was original concept of structured programming vs step by step Spaghetti Coding. There is a belief that multiple exit-point functions require more code since you have to do proper clean up of memory spaces allocated for variables. Consider a scenario where function allocates variables (resources) and getting out of the function early and without proper clean up would result in resource leaks. In addition, constructing clean-up before every exit would create a lot of redundant code.

Gringo Suave
  • 29,931
  • 6
  • 88
  • 75
PSS
  • 5,561
  • 5
  • 28
  • 30
6

I used to be an advocate of single-exit style. My reasoning came mostly from pain...

Single-exit is easier to debug.

Given the techniques and tools we have today, this is a far less reasonable position to take as unit tests and logging can make single-exit unnecessary. That said, when you need to watch code execute in a debugger, it was much harder to understand and work with code containing multiple exit points.

This became especially true when you needed to interject assignments in order to examine state (replaced with watch expressions in modern debuggers). It was also too easy to alter the control flow in ways that hid the problem or broke the execution altogether.

Single-exit methods were easier to step through in the debugger, and easier to tease apart without breaking the logic.

4

In my view, the advice to exit a function (or other control structure) at only one point often is oversold. Two reasons typically are given to exit at only one point:

  1. Single-exit code is supposedly easier to read and debug. (I admit that I don't think much of this reason, but it is given. What is substantially easier to read and debug is single-entry code.)
  2. Single-exit code links and returns more cleanly.

The second reason is subtle and has some merit, especially if the function returns a large data structure. However, I wouldn't worry about it too much, except ...

If a student, you want to earn top marks in your class. Do what the instructor prefers. He probably has a good reason from his perspective; so, at the very least, you'll learn his perspective. This has value in itself.

Good luck.

thb
  • 13,796
  • 3
  • 40
  • 68
1

The answer is very context dependent. If you are making a GUI and have a function which initialises API's and opens windows at the start of your main it will be full of calls which may throw errors, each of which would cause the instance of the program to close. If you used nested IF statements and indent your code could quickly become very skewed to the right. Returning on an error at each stage might be better and actually more readable while being just as easy to debug with a few flags in the code.

If, however, you are testing different conditions and returning different values depending on the results in your method it may be much better practice to have a single exit point. I used to work on image processing scripts in MATLAB which could get very large. Multiple exit points could make the code extremely hard to follow. Switch statements were much more appropriate.

The best thing to do would be to learn as you go. If you are writing code for something try finding other people's code and seeing how they implement it. Decide which bits you like and which bits you don't.

Flash_Steel
  • 606
  • 1
  • 6
  • 16
-6

If you feel like you need multiple exit points in a function, the function is too large and is doing too much.

I would recommend reading the chapter about functions in Robert C. Martin's book, Clean Code.

Essentially, you should try to write functions with 4 lines of code or less.

Some notes from Mike Long’s Blog:

  • The first rule of functions: they should be small
  • The second rule of functions: they should be smaller than that
  • Blocks within if statements, while statements, for loops, etc should be one line long
  • …and that line of code will usually be a function call
  • There should be no more than one or maybe two levels of indentation
  • Functions should do one thing
  • Function statements should all be at the same level of abstraction
  • A function should have no more than 3 arguments
  • Output arguments are a code smell
  • Passing a boolean flag into a function is truly awful. You are by definition doing two --things in the function.
  • Side effects are lies.
Roger Dahl
  • 15,132
  • 8
  • 62
  • 82
  • 33
    4 lines? What do you code that enables you such simplicity? I really doubt that the Linux kernel or git for example do that. – shinzou Mar 28 '16 at 22:55
  • 7
    "Passing a boolean flag into a function is truly awful. You are by definition doing two --things in the function." By definition? No... that boolean could potentially only affect one of your four lines. Also while I agree with keeping function size small, four is a bit too restrictive. This should be taken as a very loose guideline. – Jesse Jun 08 '16 at 20:08
  • 1
    @Jesse You can create two functions named for the difference in behavior that the boolean causes and factor the shared body out to a third function. `find(bool caseSensitive)` may become something like `find()`, `findCaseSensitive()` and `readChars()`. – Roger Dahl Jun 08 '16 at 23:03
  • @Roger I never said that that was never the case I said that that is not always the case. – Jesse Jun 13 '16 at 18:39
  • 12
    Adding restrictions like these will inevitably make for confusing code. It's more about methods being clean concise, and sticking to doing only what they're meant to do with no unnecessary side effects. – Jesse Jun 13 '16 at 18:42
  • @Jesse "Adding restrictions like these will inevitably make for confusing code." - I strongly disagree. it's easy to say: "keep your code clean and concise" the question is how. If you'll follow these guidelines you will discover that it enforces your code to be clean... – Nir Alfasi Aug 17 '16 at 04:58
  • 1
    @alfasin Please tell me how you keep a function that has to do all of it's own boolean logic down to four lines? `if(condition){ //line one doSomething(params); //line two } else { //line three doSomethingElse(params); //line four } // oops` – Jesse Aug 17 '16 at 13:33
  • @Jesse the fact that you do both "something" and "somethingElse" is a violation of the sixth bullet point: "Functions should do one thing" :) second, that's exactly four lines - so that's fine. Third, the recommendation was "you should try to write functions with 4 lines of code or less" - it doesn't mean that 5-6 lines method is bad. These rules mean that your code should be broken into small chewable functions, each of which is focused on doing only one thing and thus should be relatively short. Doesn't it sound reasonable to you ? A good read: http://ianjoyner.name/No_return.html – Nir Alfasi Aug 17 '16 at 15:28
  • 1
    @alfasin You have to do the logic somewhere. My example was the calling method, which required logic to know whether something, or something else was required for it to accomplish it's one task. So no , I didn't break any rules. – Jesse Aug 17 '16 at 15:59
  • @alfasin in fact that's my exact point with these constraints if/else statements, an integral part of programming cannot even be done. This is too restrictive. – Jesse Aug 17 '16 at 16:00
  • @alfasin: From your article `` sometimes contains conditionals. – Jesse Aug 17 '16 at 16:02
  • @Jesse then it should be wrapped in a separate function ;) – Nir Alfasi Aug 17 '16 at 17:48
  • @alfasin That's exactly what my example is doing, but with these constraints it is impossible. – Jesse Aug 17 '16 at 17:59
  • @alfasin In other words the code that I gave is the body of the wrapper function, it doesn't fit because of over strict constraints. There is absolutely no reason to implement such restraints that are that strict, and they will ultimately over complicate the code, entirely defeating the purpose that they were put in place for. – Jesse Aug 17 '16 at 18:01
  • @Jesse I fail to see how breaking the code into more functions will "over complicate the code". – Nir Alfasi Aug 17 '16 at 18:05
  • @alfasin I never said that it would, but nice straw man. I said that restricting every function to four lines will. Especially when you can't implement fundamental programming concepts like if... then... else logic in four lines. – Jesse Aug 17 '16 at 18:22
  • @Jesse restricting the size of a function forces you to keep breaking it to smaller chunks. Following the "only do one thing" does the same. This is not a straw - this is the concept of clean code. – Nir Alfasi Aug 17 '16 at 18:25
  • In fact whenever you are counting lines of code, you are probably doing something wrong. Keep them short and sweet, yes... Keep them clean and concise, yes... One method performs one task, yes.... Restrict the lines of code allowed in one function, No, do not do this. – Jesse Aug 17 '16 at 18:25
  • You keep going back to the "4 lines" which was the OPs interpretation. From the book: "The first rule of functions is that they should be small. The second rule of functions is that they should be smaller than that. Functions should not be 100 lines long. Functions should hardly ever be 20 lines long." I hope that 20 lines make you happier – Nir Alfasi Aug 17 '16 at 18:27
  • @alfasin I'm not sure what it is that's confusing you here, but I'm not going to get into an argument on StackOverflow because you fail to understand a simple proof of this four line restriction to be unobtainable. Have a good day. – Jesse Aug 17 '16 at 18:28
  • @alfasin again... Nice straw man. I was clear from the get go that I was not defending 100 line functions and that I was pointing out the flaws in these restrictions yes I keep going back to "4 lines" because that's what my argument has been from the start. It's you that failed to recognize that. – Jesse Aug 17 '16 at 18:30
  • For the record it's rare that I write a twenty line function. – Jesse Aug 17 '16 at 18:31
  • @Jesse your last comment made *me* happier. I think that we're on the same page after all. Have a good one! – Nir Alfasi Aug 17 '16 at 18:37
  • @alfasin Yes, I think that too. I'm not advocating long functions. I'm saying don't limit yourself to something unrealistic (4 lines in this case), and even when you have a more realistic thing, like 20 lines it's not a hard and fast rule. If you run into a situation that to complete the single task at hand it's going to take 23 lines, and there's not a great logical chunk of code that would make a good function, then you bend the rule a bit and write your 23 line function. With a restriction of 4 lines you would break that rule far too often, that's why I didn't like it. – Jesse Aug 18 '16 at 17:05
  • @Jesse I agree with you 100% (your last comment). I believe that none of these so called "rules" is a "hard rule" - it's more like a "rule of thumb", something to aim to - but not set in stone. – Nir Alfasi Aug 18 '16 at 19:14
  • Bear in mind that the number of lines, as an indicator, is also language dependent: in Python, for example, which is much more expressive than Java, if you write a 20 lines function - it is considered as relatively long, while in Java it would make much more sense because the language is more verbose. – Nir Alfasi Aug 18 '16 at 19:23
  • 1
    Yeah because an object with ten thousand methods is so much better.. – funct7 Jan 25 '17 at 07:32
  • 13
    One of the rare answers on SO that I wish I could downvote multiple times. – Steven Rands Apr 12 '17 at 13:45
  • 6
    This is dumb. Functions only make sense if you reuse them or plan to share with others. What is your gain if you split an 80 line function into 20 sub functions that are only used by one function? – sarrrrek Jan 18 '19 at 09:21
  • 1
    @sarrrrek When you split the function up, you get to name the separate parts (in the new function names). You get to potentially give more specific names to the values that are handled there (since the function argument names can be different from the ones you call the function with). You get to show more clearly which values are relevant in different parts (since you only pass the required values to the new functions). You get to avoid deep nesting (in a loop, you can call a new function instead of having a new nested code block). You get to use fewer comments (comments go stale over time). – Roger Dahl Jan 19 '19 at 03:06
  • 1
    @sarrrrek Also, when you split up the function, you get to unit test the parts separately, which usually allows writing fewer. simpler and more accurate tests. You end up doing fewer tests overall (for instance 3 + 3 + 3 = 9 separated tests instead of 3 * 3 * 3 = 27 combined tests). – Roger Dahl Jan 19 '19 at 03:20
  • 13
    Unfortunately this answer is doing multiple things and probably needed to be split up into multiple others—all less than four lines. – Eli Jun 11 '19 at 16:35