12

I'm wondering if there has been any research (both casual and robust) on the maintainability of projects that use the "guard statement" paradigm vs. the "single function exit point" paradigm?

Guard statement example (in C#):

string GetSomeString()
{
    if(necessaryConditionFails) { return null; }
    if(!FunctionWithBoolReturn(someAttribute)) { return null; }
    //all necessary conditions have been met
    //do regular processing...
    return finalStringValue;
}

single function exit point example (in C#):

string GetSomeString()
{
    string valueToReturn = null;
    if(necessaryConditionPasses && FunctionWithBoolReturn(someAttribute)) 
    { 
        //all necessary conditions have been met
        //do regular processing...
        valueToReturn = finalStringValue;
    }
    return valueToReturn;
}

I know the merits and failings of both have been debated endlessly on SO, but I'm looking for actual research into how maintainable each paradigm is*. This may be unknown, but I figured if the information is out there, someone on SO would know where it was. My web searches have not been sucessful so far.

**I'm also aware that many programmers (including me) use both principles throughout their code, depending on the situation. I'm just hoping to discover which one has a proven track record of greater maintainability to use as the preferred paradigm.*

jball
  • 24,791
  • 9
  • 70
  • 92
  • After extensive searching, and given the absence of links to hard research in the single answer to this question, it seems that there is no publically accessible research about the maintainability of code written under one paradigm versus the other. – jball Jul 07 '11 at 22:14

1 Answers1

15

Forcing to have single exit points have some problems of their own.

The first one is that it may lead to complex constructions. Image a function in which you have to open a file, read a line, convert the line to a number and return that number or zero if something goes wrong. With a single exit point, you end up using lots of nested if's (if file exists open it, if open succeeds read the line, if read succeeds convert the value to an integer), which makes your code unreadable. Some of it can be solved by having a label at the end of the function and using goto's (we had to use that in the past since we also used the single exit point and preferred readability) but it's not ideal.

Second, if you are using exceptions you are forced to catch everything if you want your single exit point again.

So, personally, I prefer putting lots of checks (and asserts) in the beginning and during the execution of the function, and exit the function at the first sign of trouble.

Patrick
  • 23,217
  • 12
  • 67
  • 130
  • 18
    +1 The advocates of "single exit point" rarely seem to realize that each place where an exception can be thrown is a potential exit point. The origin of the recommendation seems to have come from the bad old days before destructors, auto_ptr, garbage collection, and "finally" made it a lot easier to ensure your code cleans up after itself. – Theran Feb 19 '10 at 04:36
  • 2
    I think that the open file reader is exactly the scenario where one would want to do a single exit point: At the top of your file you define a variable to hold the return value, you then have a number of nested blocks. The outer most one is opening the file. If the open fails you set a status code as the return value, else you work with the open file and at the very end you close the file and free memory. Since every path through the block will hit the close file code, you ensure no leaks (as opposed to having to free resources at every exit point and risk a leak). – Konstantin Tarashchanskiy Feb 22 '12 at 19:07
  • 1
    @KonstantinNaryshkin that feels more like what finally is for. Ensuring that something always happens such as closing a file. Additionally, I've been looking into F# and I really like what [computation expressions](http://msdn.microsoft.com/en-us/library/dd233182.aspx) have to offer in the way of solving this kind of problem. (Similarly with monads in Haskell) – Steve Jul 26 '12 at 20:38
  • 3
    Martin Fowler's [Guard Clauses](http://www.refactoring.com/catalog/replaceNestedConditionalWithGuardClauses.html) is a good rule of thumb, and I this applies for throwing exception in the first line of the code. – OnesimusUnbound Aug 11 '12 at 01:14
  • 1
    I always learnt that if you are repeating things too often, chances are you are not structuring properly. So if you are writing many return statements, chances are you'd be better of writing a validation method giving you one final result to check. Then you could still opt to use either method as they'd still look better. On top you might even re-use that validation code. – Lawrence Oct 22 '13 at 09:45
  • 2
    It may also be worthwhile to note what "single exit point" really means in comparison to the looser approaches which used to be commonplace before languages supported subroutine calls. In a language which supports function calls, unless the programmer uses something like setjmp/longjmp, the exit point from a call to "foo" will be *the code immediately following the call*. The concept that each function call should return to the spot following the call may seem so obvious as to not need mention, but... – supercat Dec 06 '16 at 20:56
  • 1
    ...in machine code, especially on systems with very limited stacks, it's hardly a given. Further, constructs like setjmp/longjmp and exceptions can add additional ways by which a function can exit. – supercat Dec 06 '16 at 20:56