Fog Creek Software
Discussion Board




Multiple Exit Points

Is there a name for the general rule that functions or methods shouldn't have multiple exit points?

John Topley
Monday, February 24, 2003

If there is i break that rule :)

I often have functions with 2 exit points, like this:

function FooBar(Data : TSomeData);
begin
  if not CheckSomethingWeNeed then begin
    mylog('error blah blah blah');
    Result:=FALSE;
  end;
  ......
  ......
  ......
  mylog('success blah blah blah');
  Result:=TRUE;
end;

This would be having multiple exit points, one for failure and one for success. If you didnt do it this way, what could you do to have a single exit-point? Using goto's and local variables to indicate success or failure?

Maybe Im missing something, but this is how I do it :)

Patrik
Monday, February 24, 2003

When shall I learn never to post code to discussion boards? :) ... buggy code, but it serves as an example :)

Patrik
Monday, February 24, 2003

Many texts like code -complete etc advocate a single return from a method

anon
Monday, February 24, 2003

It's called structured programming and dates from the Eighties.

David Carlson
Monday, February 24, 2003

I think this concept was promoted as part of structured programming.  It may have been around earlier.


>>> If you didnt do it this way, what could you do to have a single exit-point?  <<<

"else" should take care of most cases.

mackinac
Monday, February 24, 2003

Patrik,

Pascal?  Cool!

Actually, my idea of multiple exit points is more like:

function Foo(InVar: Integer): Boolean;
begin
  if InVar = 1 then
    begin
      DoSomething;
      Result := True;
      Exit;
    end;
  DoSomethingElse;
  Result := Whatever;
end;

In the above, the function exits specifically because you told it to, not because it encountered the final "end".  Thus, there are two different ways of exiting the function.

I guess purists would argue that having only one exit point is a programming best practice, but in reality it can lead to structures later in a function that make the code less readable.

In my code, first I try to do only one thing with each routine.  This can eliminate a lot of multiple-exit scenarios.  If I do need a multiple exit, I find its usually because of some condition for which I can check early in the function.  This mitigates the impact somewhat.

Karl Perry
Monday, February 24, 2003

It came from the sense that branching makes proving code correct impossible and that if you have multiple exits you back that 'impossible to proveness' up the stream into the calling function, etc, etc.

I usually try and have a single exit in any one function or procedure (though as calls out of the procedure might themselves cause cascading errors that bypass the whole flow I'll ignore that).

In single valued function languages that can prove awkward as you end up having to maintain a status and the return value(s) somehow.  So you end up with hStatus returns and passing pointers around or arrays or whatever.

See MS-Windows  :-)

For languages that can return more than one value at a time its easy peasy.

The single exit doctrine tends cause errors when you have macroed code, class generators and the like, they usually stick an assignment like hStatus = APP_SUCCESS or similar, which is marginally better than having it unassigned but can be forgotten in the rush to write the code.

So you end up forgetting to assign the failure code before taking the early bath,  (Lancashire for an early return), and a failure becomes a success.  So I usually reverse that logic and have it set the status to failure as the default.

Simon Lucy
Monday, February 24, 2003

Let's say I have a function which validates an input. I have half a dozen simple tests. My choices are a lot of nested if statements, a status variable or multiple exit points. In some cases multiple exit points leads to simpler clearer code. Perhaps we can discuss the merrits of GoTo next. ;-)

John Ridout
Monday, February 24, 2003

I am confused about the question, does the original poster mean returning multpile values (IE multiple output vars) or does he mean mutiple places a method can exit, IE a select statement with many possible return values?

Ian Stallings
Monday, February 24, 2003

I like the rule of thumb that if the whole function can be viewed on screen without scrolling, multiple exit points are just fine.  But for a large function (> 1 page), multiple exits can make it more unreadable, so a single exit is preferred.

Nick
Monday, February 24, 2003

The validation of errors case is quite common.

Go to makes things easy to read and lets you clean up. I used to think goto was evil, but after trying to use if-then-else and while (0) break and other tricks, it actually makes sense.

Basically every line of code which could fail but shouldn't gets wrapped in something like Test(function());. Test is a macro which expands out to error = function(); if error != noerror goto end. End then frees memory, etc, and can possibly clean up the error code based on state. Even expected errors can say 'goto end'. No other gotos are allowed.

On short (< 10 line) functions, I'll use multiple returns.

Of course exception handling is the more modern approach. Do exeptions count as multiple exit points?

mb
Monday, February 24, 2003

Say, we have a function that takes a number as an argument and if the pointer is 0 we don't need to do anything, just have to return 0.

So, single-return way to do it is

int foo(int arg)
{
    int result;
    if (x != 0) {
        .
        .    
        .
        .
        .
        /* calculating result */
    }
    return result;
}

The multiple-return approach is

int foo(int arg)
{
    if (x == 0) return 0;
    .
    .
    .
    .
    .
    return /* calculated result */
}

I like the second code better, as it
a) expresses the intent clearly;
b) if the code takes more than a page, enclosing all of it in the 'if' scope just doesn't look good. The second approach gives code that is easier to read.

raindog
Monday, February 24, 2003

There are some instances where multiple exit points enhance code readability.

The conventional wisdom I've received is:  Minimize multiple exit points.

If you have to have 'em, that's okay.  But use them as little as possible.  Steve McConnell writes much more about this in "Code Complete."

Brent P. Newhall
Monday, February 24, 2003

Anon,

Actually, Code Complete advocate Patriks style.

He gives two reasons:

Its more readable - its obvious that the routine is supposed to finish right there.

Its safer.  If the function were to continue, there is a danger that some more code could be run, especially if extra code is appended on the end.

I'd give chapter and verse, but I'm moving house right now.

Ged Byrne
Monday, February 24, 2003

Oh yes, and it reduces the need for indenting.

Ged Byrne
Monday, February 24, 2003

A warning to those VB'ers who use GoTo's to go to the single exit point of a function, .NET does not allow goto's so you will need to change your whole exit strategy.

I know, because it happened to me.

Realist
Monday, February 24, 2003

The same applies to GoSub.

Realist
Monday, February 24, 2003

Another approach...

int foo()
{
    int retval = 1;
    ...
    // initialise stuff
    char* pchars = new char[40];

    try
    {
        if(exitCondition)
        {
            retval = 0;
            throw false;
        }
        .
        .
        .
    }
    catch(...)
    {}
   
    // cleanup stuff
    delete [] pchars;
    ...

    return retval;
}

Andrew Reid
Monday, February 24, 2003

Realist re: goto: Exactly why I (and Andrew Reid) mentioned exception handling. That's the way to do it in .NET, since everything around you will be throwing exceptions.

Mind you my experience in VB or VB.Net

mb
Monday, February 24, 2003

Andrew, there are some problems with that code. You're masking potentially serious exceptions by catching everything and not handling it. Secondly, if you're trying to protect resources, use auto_ptr<> instead. Finally, I think that exceptions should be used as a mechanism to handle unexpected errors, not as some sort of goto-on-steroids.

Frederik Slijkerman
Monday, February 24, 2003

Good point on the exception masking.

Andrew Reid
Monday, February 24, 2003

My company recently established coding standards that require a single exit point, over my objections. As a result, my code takes longer to write but is becoming more readable.

I avoid placing more than four or so levels of nested braces in any method. Keeping a single exit point forces me to create smaller methods that are generally more readable. However, it takes longer to figure out how to organize my code cleanly while obeying the single-exit-point restriction.

Julian
Tuesday, February 25, 2003

I'm amused by the idea that reducing indenting does anything to reduce complexity. 

In relation to the 'goto'.  Switches tend (if not absolutely always), to compile down to an unconditional branch, its just that the language masks that and lets us maintain the fiction that we aren't using a local goto.

Simon Lucy
Tuesday, February 25, 2003

A single exit point can be a strong suggestion at most.

And the goto... sometimes not considered harmful, in my book.  Sometimes a goto makes much more fun than trying to break/continue a while-loop while deep in some nested for-loops or something.

And consider computed gotos.  Without them, VM performance would be crap..

nice
Tuesday, February 25, 2003

The rule here is "one exit point". Mostly because there's no use of smart pointers and C++ stack objects and things so the clean-up is "hard" without that.

This leads to enourmous long routines where every operation has a "if (successful_to_this_point) { successful_to_this_point=do_something(); }

Yum.

And of course, it's an ABSOLUTE unbreakable rule, so people jump through ridiculous hoops to obey it...

Gotta love those rules to dumb development down with the intention that you can not only regard all the developers as interchange with each other, but with random strangers off the streets as well.

Katie Lucas
Tuesday, February 25, 2003

We've been having this religious war at work, particularly with early exits in VB.

For my money's worth, I'm going to write this sort of code :

Private Function FindByName(ByVal mc As clsMyCollection, ByVal strMatch As String) As clsMyObject
    ' Given the object mc, which is a collection class of
    ' clsMyObject, return the first clsMyObject where the
    ' .Name parameter equals strMatch. Return Nothing
    ' if not found
    Dim mo As clsMyObject
    For Each mo In mc
        If mo.Name = strMatch Then
            Set FindByName = mo
            Exit For
        End If
    Next
End Function

My colleague, on the other hand, insists on doing this :

Private Function FindByName(ByVal mc As clsMyCollection, ByVal strMatch As String) As clsMyObject
    ' Given the object mc, which is a collection class of
    ' clsMyObject, return the first clsMyObject where the
    ' .Name parameter equals strMatch. Return Nothing
    ' if not found
    Dim mo As clsMyObject
    Dim moReturn As clsMyObject
    Dim blnFound As Boolean
    Dim lngCounter As Long
    lngCounter = 1

    Set moReturn = Nothing

    Do While lngCounter < mc.Count And Not blnFound
        If mo.Name = strMatch Then
            Set moReturn = mo
            blnFound = True
        End If
        lngCounter = lngCounter + 1
    Loop

    Set FindByName = moReturn

End Function

... thus ensuring a single exit point. Personally, I find the second example much harder to read.

Better than being unemployed...
Tuesday, February 25, 2003

Dood, that's not a multiple exit point, it's just a "break;" in C.  That's not structured programming any more?  I'm gonna hafta rewrite a lot of my code now ...

Anyhow, that religious war is simply insane, in my opinion.  Advocates of the second implementation are obeying the letter of the law and not the spirit.  The second a coding standard causes me to write something barbaric is the second I toss the coding standard out the window.

If I absolutely *had* to eschew the use of Exit For, I'd use your code, comment out the Exit For, and tell them to deal with the performance decrease.

Alyosha`
Tuesday, February 25, 2003

I have heard the term SESE for Single Entry - Single Exit to describe this kind of code layout.

Oliver Anhuth
Tuesday, February 25, 2003

Here is what I do

bool IsError = true;

do
{
    if ( x == 0 )
    {
        break;
    }

    if ( x == 1 )
    {
        break;
    }
 
    ....  // more and more checks and calls

    IsError = false;
} while( false );

if ( IsError == true )
{
}
else
{
}

Gregor Brandt
Tuesday, February 25, 2003

Gregor,

That's some ugly code. You're using a looping construct that never actually loops just so that you can use the break keyword? That's crazy. Use a goto, for goodness sakes. That's what it's there for.

Benji Smith
Tuesday, February 25, 2003

Somoene posted that for short functions, they think multiple exit points are fine, but for long functions they think multiple exit points are bad.  I'd have to disagree with this.  In my opinion, longer functions is where multiple exit points shine.  Having large nested if statements instead of a simple
if (condition1) return;
if (condition2) return;
... real code ...

tends to make things much less readable.  Reading large functions with big nested if constructs tends to be very difficult, because it becomes hard to keep track of what condition you are in.

Anyway, I use early exit all the time.  I think it often makes for more readable code.  There are tradeoffs however.  It is slightly less safe with regards to resource handling (though this isn't hard to take care of if you're careful).  On the other hand, it is slightly more safe in the sense that you can easily tell that no code beyond a certain point will be executed in an error condition.  The second goal can also be accomplished using "goto ErrorExitCode", but I usually reserve that for cases where I have to do a lot of cleanup before the function exits.

Also another point... early exit in the case of error conditions can often be done before any resource allocation takes place in the function.  In this situation, it makes the function even safer because you never have to think about what happens to the allocated memory in an error case.

Anyway, I think in large part it depends on how you think about things.  Early exit tends to agree with me, because I tend to think about things as..
"Check for error condition 1... If we fail Bail Out! if not, forget about condition 1 forever"
and that exactly corresponds to early return

Mike McNertney
Tuesday, February 25, 2003

I no longer worry about the issue in this thread; instead, I write code using more, shorter classes and methods, each well-named and with a cohesive purpose.  As a result, the methods are short enough that noone will overlook multiple exit points anyway.

Kyle Cordes
Tuesday, February 25, 2003

I do what Gregor showed above. I think its a great compromise. 
It got bashed at my first MS code review, but pretty soon I saw it in other peoples code. It's just too nice.
The compiler "gets it" too.  Dont forget that even if you dont, the compiler uses goto.

Its better than a goto because the exit location is clear and well defined. Its much better than nested if thens because there is only one level of depth.

I generally use it when validating something complicated.
And I also put the break on the same line, if its not a long line

result = 0;
do
{
if ( 0 == a ) || ( 0 == b ) break;
if ( 0 == a->wilma ) break;
if ( 0 == b->betty ) break;
pebbles = fred(a->wilma);
bambam = bary( b->betty );

if ( !pebbles || !bambam ) break;
result = "too much flintstones!";
} while( 0 )
return result;

B
Wednesday, February 26, 2003

-------------------------------------------
I'm amused by the idea that reducing indenting does anything to reduce complexity.
-------------------------------- Simon Lucy

It doesn't reduce complexity - it improves readability.

Of course, if you're reducing indenting where it is needed - thats really missing the point.

Ged Byrne
Wednesday, February 26, 2003

Hey dweebs ..try LISP its cool.

(defun foo (a b c)
  (if (> a c)
    a
  (values (+ a b) (-b a) (*b a) a b c)))

whats wrong with multiple exit points, gotos or global variables?
Nothing except for the religious freaks that will tell you otherwise. (goto is the devil's spwan  etc)

simon
Wednesday, October 29, 2003

*  Recent Topics

*  Fog Creek Home