I often talk to programmers who say "Don't put multiple return statements in the same method." When I ask them to tell me the reasons why, all I get is "The coding standard says so." or "It's confusing." When they show me solutions with a single return statement, the code looks uglier to me. For example:

if (condition)
   return 42;
   return 97;

"This is ugly, you have to use a local variable!"

int result;
if (condition)
   result = 42;
   result = 97;
return result;

How does this 50% code bloat make the program any easier to understand? Personally, I find it harder, because the state space has just increased by another variable that could easily have been prevented.

Of course, normally I would just write:

return (condition) ? 42 : 97;

But many programmers eschew the conditional operator and prefer the long form.

Where did this notion of "one return only" come from? Is there a historical reason why this convention came about?

  • 24
    This is somewhat connected to Guard Clause refactoring. stackoverflow.com/a/8493256/679340 Guard Clause will add returns to the beginning of your methods. And it makes code a lot cleaner in my opinion. Dec 14 '13 at 9:14
  • 13
    It came from the notion of structured programming. Some may argue that having just one return allows you to easily modify the code to do something just before returning or to easily debug. May 14 '16 at 11:39
  • 9
    i think the example is a simple enough case where i wouldn't have a strong opinion one way or the other. the single-entry-single-exit ideal is more to guide us away from crazy situations like 15 return statements and two more branches that don't return at all!
    – mendota
    Aug 18 '16 at 19:15
  • 5
    That is one of the worst articles I have ever read. It seems like the author spends more time fantasising about the purity of his OOP than actually figuring out how to achieve anything. Expression and evaluation trees have value but not when you can just write a normal function instead.
    – DeadMG
    Jan 2 '19 at 22:23
  • 39
    You should remove the condition altogether. The answer is 42. Mar 15 '19 at 16:03

13 Answers 13


"Single Entry, Single Exit" was written when most programming was done in assembly language, FORTRAN, or COBOL. It has been widely misinterpreted, because modern languages do not support the practices Dijkstra was warning against.

"Single Entry" meant "do not create alternate entry points for functions". In assembly language, of course, it is possible to enter a function at any instruction. FORTRAN supported multiple entries to functions with the ENTRY statement:

      R = SQRT(X*X + Y*Y)
      ENTRY S2(R)

      CALL S(3,4)
      CALL S2(5)

"Single Exit" meant that a function should only return to one place: the statement immediately following the call. It did not mean that a function should only return from one place. When Structured Programming was written, it was common practice for a function to indicate an error by returning to an alternate location. FORTRAN supported this via "alternate return":

      SUBROUTINE QSOLVE(A, B, C, X1, X2, *)
      DISCR = B*B - 4*A*C
      IF DISCR .LT. 0 RETURN 1
      SD = SQRT(DISCR)
      DENOM = 2*A
      X1 = (-B + SD) / DENOM
      X2 = (-B - SD) / DENOM

      CALL QSOLVE(1, 0, 1, X1, X2, *99)

Both these techniques were highly error prone. Use of alternate entries often left some variable uninitialized. Use of alternate returns had all the problems of a GOTO statement, with the additional complication that the branch condition was not adjacent to the branch, but somewhere in the subroutine.

Thanks to Alexey Romanov for finding the original paper. See http://www.cs.utexas.edu/users/EWD/ewd02xx/EWD249.PDF, page 28 (printed page number is 24). Not limited to functions.

  • 80
    And don't forget spaghetti code. It was not unknown for subroutines to exit using a GOTO instead of a return, leaving the function call parameters and return address on the stack. Single exit was promoted as a way to at least funnel all the code paths to a RETURN statement.
    – TMN
    Nov 10 '11 at 15:52
  • 6
    @TMN: in the early days, most machines didn't have a hardware stack. Recursion generally wasn't supported. Subroutine arguments and return address were stored in fixed locations adjacent to the subroutine code. Return was just an indirect goto. Nov 10 '11 at 16:33
  • 8
    @kevin: Yeah, but according to you this doesn't even mean anymore what it was invented as. (BTW, I'm actually reasonably sure that Fred asked were the preference for the current interpretation of "Single Exit" comes from.) Also, C has had const since before many of the users here were born, so no need for capital constants anymore even in C. But Java preserved all those bad old C habits.
    – sbi
    Nov 10 '11 at 22:08
  • 6
    So do exceptions violate this interpretation of Single Exit? (Or their more primitive cousin, setjmp/longjmp?) Nov 22 '11 at 1:13
  • 3
    Even though the op asked about the current interpretation of single return, this answer is the one with the most historical roots. There's no point in using a single return as a rule, unless you want your language to match the awesomeness of VB (not .NET). Just remember to use non-short-circuit boolean logic as well.
    – acelent
    Nov 29 '12 at 0:44

This notion of Single Entry, Single Exit (SESE) comes from languages with explicit resource management, like C and assembly. In C, code like this will leak resources:

void f()
  resource res = acquire_resource();  // think malloc()
  if( f1(res) )
    return; // leaks res
  release_resource(res);  // think free()

In such languages, you basically have three options:

  • Replicate the cleanup code.
    Ugh. Redundancy is always bad.

  • Use a goto to jump to the cleanup code.
    This requires the cleanup code to be the last thing in the function. (And this is why some argue that goto has its place. And it has indeed – in C.)

  • Introduce a local variable and manipulate control flow through that.
    The disadvantage is that control flow manipulated through syntax (think break, return, if, while) is much easier to follow than control flow manipulated through the state of variables (because those variables have no state when you look at the algorithm).

In assembly it's even weirder, because you can jump to any address in a function when you call that function, which effectively means you have an almost unlimited number of entry points to any function. (Sometimes this is helpful. Such thunks are a common technique for compilers to implement the this pointer adjustment necessary for calling virtual functions in multiple-inheritance scenarios in C++.)

When you have to manage resources manually, exploiting the options of entering or exiting a function anywhere leads to more complex code, and thus to bugs. Therefore, a school of thought appeared that propagated SESE, in order to get cleaner code and less bugs.

However, when a language features exceptions, (almost) any function might be exited prematurely at (almost) any point, so you need to make provisions for premature return anyway. (I think finally is mainly used for that in Java and using (when implementing IDisposable, finally otherwise) in C#; C++ instead employs RAII.) Once you have done this, you cannot fail to clean up after yourself due to an early return statement, so what is probably the strongest argument in favor of SESE has vanished.

That leaves readability. Of course, a 200 LoC function with half a dozen return statements sprinkled randomly over it is not good programming style and does not make for readable code. But such a function wouldn't be easy to understand without those premature returns either.

In languages where resources are not or should not be managed manually, there is little or no value in adhering to the old SESE convention. OTOH, as I have argued above, SESE often makes code more complex. It is a dinosaur that (except for C) does not fit well into most of today's languages. Instead of helping the understandability of code, it hinders it.

Why do Java programmers stick to this? I don't know, but from my (outside) POV, Java took a lot of conventions from C (where they make sense) and applied them to its OO world (where they are useless or outright bad), where it now sticks to them, no matter what the costs. (Like the convention to define all your variables at the beginning of the scope.)

Programmers stick to all kinds of strange notations for irrational reasons. (Deeply nested structural statements – "arrowheads" – were, in languages like Pascal, once seen as beautiful code.) Applying pure logical reasoning to this seems to fail to convince the majority of them to deviate from their established ways. The best way to change such habits is probably to teach them early on to do what's best, not what's conventional. You, being a programming teacher, have it in your hand. :)

  • 63
    Right. In Java, cleanup code belongs in finally clauses where it gets executed regardless of early returns or exceptions.
    – dan04
    Nov 9 '11 at 9:41
  • 18
    @dan04 in Java 7 you don't even need the finally most of the time. Nov 9 '11 at 9:45
  • 108
    @Steven: Of course you can demonstrate that! In fact, you can show convoluted and complex code with any feature that can also be shown to make code simpler and easier to understand. Everything can be abused. The point is to write code so that it is easier to understand, and when that involves throwing SESE out the window, so be it, and damn the old habits that applied to different languages. But I wouldn't hesitate to control execution by variables either if I'd think it made the code easier to read. It's just that I cannot remember having seen such code in almost two decades.
    – sbi
    Nov 9 '11 at 12:31
  • 23
    @Karl: Indeed, it is a severe shortcoming of GC languages like Java that they relieve you from having to clean up one resource, but fail with all the others. (C++ solves this problem for all resources using RAII.) But I wasn't even talking of only memory (I only put malloc() and free() into a comment as an example), I was talking about resources in general. I also wasn't implying GC would solve these problems. (I did mention C++, which doesn't have GC out of the box.) From what I understand, in Java finally is used to solve this problem.
    – sbi
    Nov 9 '11 at 14:15
  • 12
    @sbi: More important for a function (procedure, method, etc.) than being no more than a page long is for the function to have a clearly defined contract; if it's not doing something clear because it's been chopped up to satisfy an arbitrary length constraint, that's Bad. Programming is about playing off different, sometimes conflicting forces against each other. Nov 22 '11 at 14:20

On the one hand, single return statements make logging easier, as well as forms of debugging that rely on logging. I remember plenty of times I had to reduce the function into single return just to print out the return value at a single point.

  int function() {
     if (bidi) { print("return 1"); return 1; }
     for (int i = 0; i < n; i++) {
       if (vidi) { print("return 2"); return 2;}
     print("return 3");
     return 3;

On the other hand, you could refactor this into function() that calls _function() and logs the result.

  • 41
    I would also add that it makes debugging easier because you only ever need to set one breakpoint to catch all exits* from the function. I beleive that some IDEs let you put a breakpoint on the close brace of the function to do the same thing. (* unless you call exit)
    – Skizz
    Nov 10 '11 at 11:03
  • 6
    For a similar reason, it also makes it easier to extend (add to) the function, since your new functionality doesn't have to be inserted before each return. Say you needed to update a log with the result of the function call, for example.
    – JeffSahol
    Nov 10 '11 at 16:43
  • 80
    Honestly, if I were maintaining that code, I'd rather have a sensibly-defined _function(), with returns at appropriate places, and a wrapper named function() that handles extraneous logging, than have a single function() with contorted logic to make all returns fit into a single exit-point just so I can insert an additional statement before that point.
    – ruakh
    Nov 13 '11 at 19:41
  • 14
    In some debuggers (MSVS) you can put breakpoint on last closing brace
    – Abyx
    Nov 21 '11 at 21:56
  • 10
    printing != debugging. That's not argument at all. Dec 14 '13 at 9:08

"Single Entry, Single Exit" originated with the Structured Programming revolution of the early 1970s, which was kicked off by Edsger W. Dijkstra's letter to the Editor, GOTO Statement Considered Harmful. The concepts behind structured programming were laid out in detail in the classic book Structured Programming by Ole Johan-Dahl, Edsger W. Dijkstra, and Charles Anthony Richard Hoare.

"GOTO Statement Considered Harmful" is required reading, even today. "Structured Programming" is dated, but still very, very rewarding, and should be at the top of any developer's "Must Read" list, far above anything from e.g. Steve McConnell. (Dahl's section lays out the basics of classes in Simula 67, which are the technical foundation for classes in C++ and all of object-oriented programming.)

  • 8
    The article was written in days before C when GOTO's were used heavily. They aren't the enemy, but this answer is definitely correct. A return statement thats not at the end of a function is effectively a goto.
    – user606723
    Nov 9 '11 at 15:21
  • 41
    The article was also written in the days when goto could literally go anywhere, like right into some random point in another function, bypassing any notion of procedures, functions, a call stack, etc. No sane language permits that these days with a straight goto. C's setjmp/longjmp is the only semi-exceptional case i'm aware of, and even that requires cooperation from both ends. (Semi-ironic that i used the word "exceptional" there, though, considering that exceptions do almost the same thing...) Basically, the article discourages a practice that's long dead.
    – cHao
    Nov 9 '11 at 15:41
  • 5
    From the last paragraph of "Goto Statement considered harmful": "in [2] Guiseppe Jacopini seems to have proved the (logical) superfluousness of the go to statement. The exercise to translate an arbitrary flow diagram more or less mechanically into a jump-less one, however, is not to be recommended. Then the resulting flow diagram cannot be expected to be more transparent than the original one."
    – hugomg
    Nov 9 '11 at 18:22
  • 11
    What does this have to do with the question? Yes, Dijkstra's work eventually led to SESE languages, and so what? So did Babbage's work. And perhaps you should re-read the paper if you think it says anything about having multiple exit points in a function. Because it doesn't.
    – jalf
    Nov 9 '11 at 18:35
  • 13
    @John, you seem to be trying to answer the question without actually answering it. It's a fine reading list, but you've neither quoted nor paraphrased anything to justify your claim that this essay and book have anything to say about the asker's concern. Indeed, outside of comments you've said nothing substantial about the question whatsoever. Consider expanding this answer.
    – Shog9
    Nov 9 '11 at 22:05

It's always easy to link Fowler.

One of the main examples that go against SESE are guard clauses:

Replace Nested Conditional with Guard Clauses

Use Guard Clauses for all the special cases

double getPayAmount() {
    double result;
    if (_isDead) result = deadAmount();
    else {
        if (_isSeparated) result = separatedAmount();
        else {
            if (_isRetired) result = retiredAmount();
            else result = normalPayAmount();
return result;


double getPayAmount() {
    if (_isDead) return deadAmount();
    if (_isSeparated) return separatedAmount();
    if (_isRetired) return retiredAmount();
    return normalPayAmount();

For more information see page 250 of Refactoring...

  • 26
    Another bad example: it could just as easily be fixed with else-ifs.
    – Jacklynn
    Jul 6 '15 at 17:58
  • 1
    Your example is not fair, how about this: double getPayAmount() { double ret = normalPayAmount(); if (_isDead) ret = deadAmount(); if (_isSeparated) ret = separatedAmount(); if (_isRetired) ret = retiredAmount(); return ret; };
    – Charbel
    Apr 22 '16 at 6:55
  • 9
    @Charbel That's not the same thing. If _isSeparated and _isRetired can both be true (and why wouldn't that be possible?) you return the wrong amount.
    – hvd
    Jan 22 '17 at 9:02
  • 9
    @Konchog "nested conditionals will provide a better execution time than guard clauses" This majorly needs a citation. I have my doubts that it's reliably true at all. In this case, for example, how are early returns any different from logical short-circuiting in terms of generated code? Even if it mattered, I can't imagine a case where the difference would be more than an infinitesimal sliver. So you're applying premature optimisation by making the code less readable, just to satisfy some unproven theoretical point about what you think leads to slightly faster code. We don't do that here Sep 23 '18 at 16:09
  • 1
    @underscore_d, you are right. it depends a lot on the compiler, but it can take more space.. Look at the two pseudo-assemblies and it's easy to see why guard clauses come from high level languages. "A" test(1); branch_fail end; test(2); branch_fail end; test(3); branch_fail end; {CODE} end: return; "B" test(1); branch_good next1; return; next1: test(2); branch_good next2; return; next2: test(3); branch_good next3; return; next3: {CODE} return;
    – user269891
    Sep 24 '18 at 11:32

I wrote a blog post on this topic a while back.

The bottom line is that this rule comes from the age of languages that don't have garbage collection or exception handling. There is no formal study that shows that this rule leads to better code in modern languages. Feel free to ignore it whenever this will lead to shorter or more readable code. The Java guys insisting on this are blindly and unquestioning following a outdated, pointless rule.

This question has also been asked on Stackoverflow

  • Hey, I can't reach that link anymore. Do you happen to have a version that's hosted somewhere still accessible?
    – Nic
    Jan 22 '17 at 4:12
  • Hi, QPT, good spot. I have brought the blog post back and updated the URL above. It should link now!
    – Anthony
    Jan 28 '17 at 18:23
  • There's more to it than that though. It's much easier to manage precise execution timing by using SESE. Nested conditionals can often be refactored out with a switch anyway. It's not just about whether or not there's a return value.
    – user269891
    Apr 18 '17 at 7:15
  • 3
    Mehrdad, If there is a formal study in support of it, show it. That's all. Insisting on evidence against is shifting the burden of proof.
    – Anthony
    Jun 13 '17 at 8:10
  • 1
    Come off it, questioning the statement "There is no formal study that shows this" is a textbook case of asking for "proving a negative". A statement "there is no x" is a textbook "negative claim" which "asserts the non-existence or exclusion of something" so you're wrong about that. Also yes, pointless rules are bad when they cause extra work and lead to awkward code. If there's a good reason for it, fine. But there is not, unless you know something that we don't?
    – Anthony
    Sep 3 '20 at 13:15

One return makes refactoring easier. Try to perform "extract method" to the inner body of a for loop that contains a return, break or continue. This will fail as you have broken your control flow.

The point is: I guess that nobody is pretending to write perfect code. So code is reguarly under refactoring to be "improved" and extended. So my goal would be to keep my code as refactoring friendly as possible.

Often I face the problem that I have to reformulate functions completely if they contain control flow breakers and if I want to add only little functionality. This is very error prone as you change whole the control flow instead of introducing new paths to isolated nestings. If you have only one single return at the end or if you use guards to exit a loop you of course have more nesting and more code. But you gain compiler and IDE supported refactoring capabilities.

  • The same applies to variables. Which are the alternative to using control-flow-constructs like early return. Oct 16 '17 at 22:07
  • Variables will mostly not hinder you to break your code into pieces in a way that the existing control flow is preserved. Try "extract method". The IDEs are only able to perform control flow preserivng refactorings as they are not able to derive semantics from what you have written.
    – oopexpert
    Oct 17 '17 at 7:12

Consider the fact that multiple return statements are equivalent to having GOTO's to a single return statement. This is the same case with break statements. As thus, some, like me, consider them GOTO's for all intents and purposes.

However, I don't consider these types of GOTO's harmful and will not hesitate to use an actual GOTO in my code if I find a good reason for it.

My general rule is that GOTO's are for flow control only. They should never be used for any looping, and you should never GOTO 'upwards' or 'backwards'. (which is how breaks/returns work)

As others have mentioned, the following is a must read GOTO Statement Considered Harmful
However, keep in mind that this was written in 1970 when GOTO's were way overused. Not every GOTO is harmful and I would not discourage their use as long as you don't use them instead of normal constructs, but rather in the odd case that using normal constructs would be highly inconvenient.

I find that using them in error cases where you need to escape an area because of a failure that should never occur in normal cases useful at times. But you should also consider putting this code into a separate function so that you can just return early instead of using a GOTO... but sometimes that's also inconvenient.

  • 7
    All structured constructs that replace gotos are implemented in terms of goto. E.g. loops, "if" and "case". This does not make them bad - in fact the opposite. Also, it is "intents and purposes".
    – Anthony
    Nov 10 '11 at 15:05
  • Touche, but this doesn't differ my point... It just makes my explanation slightly wrong. oh well.
    – user606723
    Nov 10 '11 at 16:33
  • GOTO should be always okay as long as (1) target is within the same method or function and (2) the direction is forward in the code (skip some code) and (3) the target is not inside some another nested structure (e.g. GOTO from the middle of if-case to the middle of else-case). If you follow these rules, all misuses of GOTO have a really strong code smell both visually and logically. Dec 11 '12 at 11:29

Cyclomatic Complexity

I've seen SonarCube use multiple return statement for determining cyclomatic complexity. So more the return statements, the higher the cyclomatic complexity

Return Type Change

Multiple returns mean we need to change at multiple places in the function when we decide to change our return type.

Multiple Exit

It's harder to debug since the logic needs to be carefully studied in conjunction with the conditional statements to understand what caused the returned value.

Refactored Solution

The solution to multiple return statements is to replace them with polymorphism have a single return after resolving the required implementation object.

  • 12
    Moving from multiple returns to setting the return value in multiple places doesn't eliminate cyclomatic complexity, it only unifies the exit location. All the problems which cyclomatic complexity can indicate in the given context remain. "It's harder to debug since the logic needs to be carefully studied in conjunction with the conditional statements to understand what caused the returned value" Again, the logic doesn't change by unifying the return. If you have to carefully study code to understand how it works, it needs to be refactored, full stop.
    – WillD
    Mar 29 '19 at 18:37

Is there a historical reason why this convention came about?

The answer I learnt - at university, in the early 1980's - was that single entry and exit were pre-conditions to mathematical proof of correctness of code. This was deemed sufficiently important that it was part of the course.

This is a somewhat more recent (2004) writeup from Cornell in the United States: https://www.cs.cornell.edu/courses/cs312/2004fa/lectures/lecture9.htm

Language, then at least, had little or no impact on this. It was far more about your ability to assert what was, or wasn't true.

  • 2
    I think I remember SIGPLAN articles from ACM back in the late 70's early 80's about correctness proving systems that said single return made the job much easier (along with other adornments such as assertions.) Of course, we know what resulted from this effort: we learned a lot about language design but didn't end up with practical tools. I also remember the fights between the provers and the testers in those articles. We know who won that argument. Jun 10 '20 at 15:45

With only one exit point from a function you can easily add postconditions to make sure the result has the desired properties; here is an example in Oberon (which does not support early return):

    VAR result: INTEGER;
    ASSERT(n >= 0);
    result := 0;
    (*complicated logic*)
    ASSERT(result >= 0);
    ASSERT(result MOD 2 = 0)
RETURN result

With early returns you would have to add the postconditions before each return statement which makes the function hard to read and maintain.

See also https://en.wikipedia.org/wiki/Postcondition


Multiple returns introduce implicit paths in the code to just past the end of the function (or method) that are visible neither at the individual return statements, nor at the end of the function. This can cause a reviewer to misinterpret the behaviour of the code through no fault of their own. Not all functions can be inspected at a glance and having to check for additional return paths increases the possibility of error.

Where the notation is used as a form of Guard clause advocated in, among others Smalltalk, they are a form of design by contract pre-conditions. In such a case, they are only syntactically ill advised as they do not change the behaviour of the function. Each pre-condition implements a veto on continued execution and their ordering is unimportant.

In the cases attributed to Fowler, this approach is less advisable. Where guards are deterministically evaluated in order to select a behaviour, the returns make the code look like preconditions, but are not and depend on their ordering. This introduces the same state dependencies that the OP identifies as a concern with the added variable. A nested if/else statement would make the classification of cases explicit and simplify understanding.

However, where any one the true guards is nondeterministic evaluated, the notation again becomes one where all paths are equivalent and the multiple returns again become syntactic baggage that other notations could remove. This is equivalent to Horn clauses and provides a safe model for discriminating between multiple paths in a program.

Correct code outweighs pretty code in all cases.


Today, there is one practical reason: To make debugging easier. If you want to see which value a function returns, it is often easiest to store the result in a variable which is returned at the very end, so you can set a single breakpoint and check the return value. Or print it for debugging. If you have a debugger that can do better, good for you. Would be perfect to have a debugger that lets you set a breakpoint at the closing bracket of a function, but actually breaks at the return statement that’s returning and shows the value.

  • 1
    Set a breakpoint at the point of origin, where the function was called, and examine the return value there. Jun 10 '20 at 16:51
  • Robert, I would have expected better from you. f(self.prop1, self.prop2, self.prop3). Now set a breakpoint to get the return value of prop2.
    – gnasher729
    Jun 11 '20 at 13:48
  • 3
    It's not a good enough reason to upend your entire coding style. Early exit is a very useful technique; it cleans up endless if-else ladders, and greatly simplifies the logic. Jun 11 '20 at 13:53
  • Up to everyone to decide themselves. Nevertheless, your first comment was nonsense.
    – gnasher729
    Jun 11 '20 at 13:56
  • 1
    A good debugger should allow you to breakpoint all returns at once. If your debugger doesn't, consider contributing to improve it (unless it's closed-source, in which case you should probably switch). Jun 11 at 9:41

Not the answer you're looking for? Browse other questions tagged or ask your own question.