Where did the notion of "one return only" come from?

780

337

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;
else
   return 97;

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

int result;
if (condition)
   result = 42;
else
   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?

fredoverflow

Posted 2011-11-09T07:10:59.047

Reputation: 4 623

this question is discussed at metagnat 2016-02-17T07:13:49.527

1

This is somewhat connected to Guard Clause refactoring. http://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.

Piotr Perak 2013-12-14T09:14:43.337

1and where is the discussion discussed?Liviu 2016-05-13T08:58:00.833

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.martinkunev 2016-05-14T11:39:10.153

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 2016-08-18T19:15:38.547

Answers

699

"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:

      SUBROUTINE S(X, Y)
      R = SQRT(X*X + Y*Y)
C ALTERNATE ENTRY USED WHEN R IS ALREADY KNOWN
      ENTRY S2(R)
      ...
      RETURN
      END

C USAGE
      CALL S(3,4)
C ALTERNATE USAGE
      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":

C SUBROUTINE WITH ALTERNATE RETURN.  THE '*' IS A PLACE HOLDER FOR THE ERROR RETURN
      SUBROUTINE QSOLVE(A, B, C, X1, X2, *)
      DISCR = B*B - 4*A*C
C NO SOLUTIONS, RETURN TO ERROR HANDLING LOCATION
      IF DISCR .LT. 0 RETURN 1
      SD = SQRT(DISCR)
      DENOM = 1.0 / (2*A)
      X1 = (-B + SD) / DENOM
      X2 = (-B - SD) / DENOM
      RETURN
      END

C USE OF ALTERNATE RETURN
      CALL QSOLVE(1, 0, 1, X1, X2, *99)
C SOLUTION FOUND
      ...
C QSOLVE RETURNS HERE IF NO SOLUTIONS
99    PRINT 'NO SOLUTIONS'

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.

kevin cline

Posted 2011-11-09T07:10:59.047

Reputation: 27 832

66+1, this answer needs some serious up voting. Hoping it'll get a chance to compete at the top. P.s. if it would, be prepared to add some references. ;pSteven Jeuris 2011-11-09T23:30:07.303

18That's indeed interesting histoy, +1 from me. How then got "Single Exit" perverted so badly?sbi 2011-11-10T15:13:16.603

26And 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 2011-11-10T15:52:34.540

3@sbi: How? human fallibility. There are a number of other truisms which made sense at one time but are still being followed senselessly. One example is using all caps for constants in languages other than C.kevin cline 2011-11-10T16:28:47.240

1@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.kevin cline 2011-11-10T16:33:09.310

4

@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 2011-11-10T22:08:52.053

1@TMN I discovered that the hard way when learning QBASIC years and years ago!Canageek 2011-11-11T01:55:27.980

1So do exceptions violate this interpretation of Single Exit? (Or their more primitive cousin, setjmp/longjmp?)Mason Wheeler 2011-11-22T01:13:03.723

@Mason: The original article on SESE was focused on provable code. Unrestricted branching creates a combinatorial explosion in possible program states. The use of exceptions could also complicate a correctness proof, if the catch clause accesses local variables that may or may not have been initialized in the main line of code.kevin cline 2011-11-22T21:15:58.687

1+1 never has there been a more confusing and unnecessary feature in a language than the FORTRAN ENTRY statement - and there was usually a much better way to do it without using an ENTRY. I have also used the alternate entry in the past as well, which was also a bit silly.dodgy_coder 2011-12-02T02:25:45.920

5@dodgy_coder: FORTRAN had to compete with assembly language, when memory and cycles where both quite expensive. Use of ENTRY instead of splitting the function saved the memory for the additional CALL and RETURN statements, and the tens of microseconds needed to execute them.kevin cline 2011-12-02T17:44:03.077

2Even 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 2012-11-29T00:44:42.887

1

@sbi [OT] RE C & const: Bad example. const just marks a normal variable as "read-only" as an attempt to statically prevent writes to it. It's a compiler thing. It could still exist, be allocated, addressable and even modified if cast accordingly (though obviously a bad idea). In contrast, macros can be used to carry literals that don't exist past the preprocessing stage, which is very different. Thus, there is still a need for "capitalized constants" in C. Your central point still stands however; cargo-cult practices are indeed pervasive.

tne 2016-02-19T14:46:54.247

@tne: Not in C++. If possible, const integrals will be eliminated from the binary just as macros will.sbi 2016-04-19T09:53:45.993

778

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
  f2(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.

So 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. So 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.


So 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 outrightly 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.)

But 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. So 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. :)

sbi

Posted 2011-11-09T07:10:59.047

Reputation: 9 226

48Right. In Java, cleanup code belongs in finally clauses where it gets executed regardless of early returns or exceptions.dan04 2011-11-09T09:41:15.627

14@dan04 in Java 7 you don't even need the finally most of the time.R. Martinho Fernandes 2011-11-09T09:45:50.813

1+1 for the explanation of explicit resource management, I never realized that. Although, I don't agree 100% with your updates. I can easily demonstrate you code with multiple returns (and have often experienced in practice) which degrades readability.Steven Jeuris 2011-11-09T12:02:59.817

76@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 2011-11-09T12:31:53.147

@sbi: true, but I have, and that's most likely our 'difference' (which doesn't turn out to be a difference) in opinion. See for example this Code Review question. It doesn't involve return but continue, but the same principle of unreadability due to early returns applies.

Steven Jeuris 2011-11-09T12:35:44.317

@sbi: Controlling execution with variables has largely been supplanted with polymorphism (no more 'catch-all' procedures controlled by magic flags). I really only see it in state machines anymore.TMN 2011-11-09T13:36:19.837

2Great explanation, just don't neglect that memory isn't the only resource of concern. There are also file handles, database connections, mutexes, etc. that last time I checked Java doesn't clean up as automatically as it does memory, and often needs to be more deterministic than memory garbage collection, i.e. you need to guarantee the resource is released when the function exits, not at some future garbage collection sweep.Karl Bielefeldt 2011-11-09T13:45:15.393

14

@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 2011-11-09T14:15:26.247

4I know a lot of the really bad habits that my place adheres to is mainly argued for using reading printouts. They argue that you can't see type in a printout, so prefixing with type (a, str, lp), is a good thing. They argue declaring variables at the top of scope is good because you know where to look when you read the printout. I'm wondering why if meetings are all that important, we don't have tablet machines instead of printouts. Maybe I'll suggest that at a later meeting.... over a printout.Lee Louviere 2011-11-09T15:03:08.657

@sbi The tangential comments were removed (note to everyone: any criticism that takes a dozen comments to flesh out needs to be its own answer), but can you improve your answer to incorporate the responses to the comment feedback you've received here? Anything important to understanding your answer shouldn't be buried here. – None – 2011-11-09T21:36:54.310

3-1: Sorry, SESE was not initially proposed to prevent resource leaks. In C, the best practice may be to pass a function pointer to a function that allocates the resource, calls the passed function, then releases the resource.kevin cline 2011-11-09T22:14:59.577

In C#, "using" is preferred over finally, to clean up resources that implement IDisposable.Dave Van den Eynde 2011-11-10T14:55:34.190

@Dave: Indeed, I should have known that! Will fix.sbi 2011-11-10T15:10:38.820

4@kevin: "Single Exit" is used nowadays the way I described it. It might well have started out for other reasons, but SESE advocates will certainly point out that "Single Exit" is necessary for proper resource cleanup.sbi 2011-11-10T15:14:20.643

@Xaade Definetely not using the 'var' keyword in C# I guess...riezebosch 2011-11-10T15:26:34.417

1Added from personal experience: SESE certainly leads to more complicated code- monsters such as the function that ends with 17 closing braces. Also, if you define the logic of an inner conditional, often there are very bizarre derivations of what is actually being checked from the mathematical sense. For a short function, fine SESE. If it doesn't fit on a screen, don't try SESE. Ultimately it's a style thing, used to be cannon, now seen as bad. 30 years on from now we'll look at a few "best practices" of today and think "that's terrible! what were they thinking?"anon 2011-11-11T04:00:21.533

1@anon: SESE being a "cannon" is a wonderful Freudian slip. :) Anyway, any function that doesn't fit on one screen is too long.sbi 2011-11-11T08:52:42.483

9@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.Donal Fellows 2011-11-22T14:20:37.750

"So why do Java programmers stick to this?": I didn't hear this advice coming from Java programmers more often than coming from C++ or C# programmers.Giorgio 2012-11-09T12:27:16.263

4" you basically have three options" -- Wrong. I use this: ftype f() { resource res = acquire_resource(); ftype ret = f_inner(res); release_resource(res); return ret; } ... then f_inner can do all the returning it wants.Jim Balter 2013-05-10T18:50:56.807

-1: You can reach "Single Exit" in the example with void f() { resource res = acquire_resource(); if( !f1(res) ) f2(res); release_resource(res); }. The logic behind the flow becomes even clearer. I think you should look for a better example.Piovezan 2014-01-28T12:49:02.980

This answer has a few non sequiturs. I can't see how introducing a local variable to be returned at the function's end necessarily leads to manipulating control flow through it. I can't find any other argument for the statement "SESE often makes code more complex" and can't see how cyclomatic complexity is increased without performing inappropriate control flow. I don't think freeing up resources is the only argument in favor of "single exit" as during maintenance you may need to add code right before the (preferably unique) return point, not necessarily for freeing up resources (you may...Piovezan 2014-01-28T17:06:23.373

...want to call a log function or perform any other function/method call that is necessary in your flow). As a Java programmer, I find SE to be a valid extension to DRY and not a C convention to be blindly followed (defining variables at the beginning of the scope OTOH is yuck). Disliking SE to me suggests a tendency to avoid negative logic in control flow statements as well (if (!condition)) which may reflect a weakness in programming logic (negative logic statements should be harder to read, but not that much).Piovezan 2014-01-28T17:06:49.640

3@Piovezan: "I can't see how introducing a local variable to be returned at the function's end necessarily leads to manipulating control flow through it." This is such a common case that I never thought I would need to show code doing that. Think a C algorithm, where all functions invoked return an error status. That is stored in a variable err, and if one function returns an error, all the others must not be called anymore. As for the rest: I won't even attempt to reply to that.sbi 2014-01-31T09:40:56.483

You still want to do this with C++, because returning a single object lets the compiler avoid copies and moves entirely.Mehrdad 2014-05-22T08:08:07.157

2@Mehrdad: 1. Write good, easy to understand, well maintainable code. 2. Fix the bugs. 3. Test whether it's fast enough. 3a. If it is, your done. 3b. If it isn't, profile and measure to find the (few) hotspots, and sacrify readability there. Only there.sbi 2014-05-22T08:49:57.867

@sbi: Or you could just learn to do it right from the beginning so that you can structure your code readably without sacrificing the optimization or hindering debugging. I don't think I've ever seen the single-return convention harm code in some way, but I've definitely seen multiple returns rear their ugly heads when I'm trying to set a breakpoint to find what values a function is returning and inevitably end up missing one of the 4 returns in the function.Mehrdad 2014-05-22T09:34:06.500

2

@Mehrdad: I have answered to this years ago.

sbi 2014-05-22T15:40:42.063

59

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.

perreal

Posted 2011-11-09T07:10:59.047

Reputation: 331

+1 good point. Printing debugging is useful to me and this is good idea for it.user712092 2011-11-09T15:45:29.023

25I 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 2011-11-10T11:03:35.323

2For 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 2011-11-10T16:43:12.963

48Honestly, 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 2011-11-13T19:41:01.210

7In some debuggers (MSVS) you can put breakpoint on last closing braceAbyx 2011-11-21T21:56:16.870

2printing != debugging. That's not argument at all.Piotr Perak 2013-12-14T09:08:27.033

@Peri Thank you. Printing is a primitive way of debugging but this is just ridiculous. If I had the reputation on this site, I'd love to downvote this answer.spaaarky21 2014-11-26T20:16:51.520

@spaaarky21, check this out: http://blog.awilkins.id.au/2011/10/c-source-to-source-translation.html

perreal 2015-01-13T16:13:40.070

@JeffSahol Well you may never have a new functionality.. And refactoring should not be difficult if new functionality actually is implemented..Koray Tugay 2015-12-18T19:30:50.527

40

"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.)

John R. Strohm

Posted 2011-11-09T07:10:59.047

Reputation: 15 481

4The 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 2011-11-09T15:21:51.873

3@user606723 No. In most architectures, the code to return from a function is as simple as writing leave; ret (x86) or pop 1,0 (MMIX). In most cases, that is much simpler than jumping to the exit point.FUZxxl 2011-11-09T15:34:26.213

22The 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 2011-11-09T15:41:12.260

2@cHao: What Dijkstra observed was that GOTOs tended to proliferate ("multiply like cockroaches" might be a better analogy) in code, and multiple GOTOs invariably obscured the intent of the code. This was before the "structured" control structures were common, and before Bohm & Jacopini's [Google is your FRIEND!] formal proof that the structured control structures were all you needed. Today, heavy use of "break", "continue", and "return" in the middle of a random mass of code are just as effective at obfuscating the code's intent as GOTO was in the early days.John R. Strohm 2011-11-09T16:17:30.650

3Heavy use of break, continue, return and goto can obfuscate. But they have their place, and when used decently (ie: when they are appropriate), they increase readability by pruning the decision tree. The argument was against the unbridled use of goto, not against its use ever -- break/continue, being restricted, are outside of the argument's scope. But even Dijksta would have to admit that abolishing goto entirely is unrealistic -- and Wirth (who published and even named that article, and took it to heart) did admit as much when he added a goto to pretty much every language he designed.cHao 2011-11-09T17:50:25.017

5From 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 2011-11-09T18:22:14.297

8What 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 2011-11-09T18:35:46.643

4@JohnR.Strohm - if the argument is that writing return twice in one function will cause it to multiply across the code base then I think it's flawed. Just because you wrote it once in one function doesn't mean you'll unwilling have to write it a second time, in another function. That is unless the construct proved usefully expressive enough as to make it desirable, but "usefully expressive" is a whole world apart from "parasitic infestation". If the code base is so tightly coupled that it does cause this then I'd start to worry about the elephant in the room first.Flexo 2011-11-09T18:36:46.933

@missingno: Thank you for the correction. It has been many years since I read the paper, and I was not aware that Bohm & Jacopini's paper actually preceded it.John R. Strohm 2011-11-09T19:58:28.817

From the original question: "Where did this notion of "one return only" come from, and why do people adhere to it rigidly?" In other words, the original question is "Where did Single Entry/Single Exit come from?", and the answer is that it came from the Structured Programming movement of the early 1970s.John R. Strohm 2011-11-09T20:33:05.840

8@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 2011-11-09T22:05:21.157

I find it curious how coroutines (and generators) are making something of a comeback these past few years, as they definitely have the ability to violate part of SESE, albeit in a limited sense.Donal Fellows 2011-11-11T23:54:30.483

@DonalFellows: Part? :) True coroutines would seem to pretty much turn SESE on its ear. Generators, not quite so much, as they don't choose where to "yield" to; although on a conceptual level there's still a number of "entry points", most languages that use generators aren't able to actually jump straight to those entry points. Generators in those languages are really just hidden state machines.cHao 2012-10-26T15:24:40.287

16

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;
};  

                                                                                                         http://www.refactoring.com/catalog/arrow.gif

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

For more inforamtion see page 250 of Refactoring...

Pieter B

Posted 2011-11-09T07:10:59.047

Reputation: 7 645

If your conditional check decides which code path to execute, yes. For simple assignments, no.DanMan 2014-05-24T11:16:19.823

1Another bad example: it could just as easily be fixed with else-ifs.Jack 2015-07-06T17:58:36.797

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 2016-04-22T06:55:39.413

+1 For citing an specific Martin Fowler refactoring. I am working and refactoring with code from someone who followed the one return path and it is hell but can improve fast with this refactor.Borjab 2016-11-24T12:11:41.380

4

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

Anthony

Posted 2011-11-09T07:10:59.047

Reputation: 121

2

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.

user606723

Posted 2011-11-09T07:10:59.047

Reputation: 1 029

1All 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 2011-11-10T15:05:27.030

Touche, but this doesn't differ my point... It just makes my explanation slightly wrong. oh well.user606723 2011-11-10T16:33:18.017

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.Mikko Rantalainen 2012-12-11T11:29:35.860