tags:

views:

1012

answers:

12

In C, C++ and C# when using a condition inside a function or loop statement it's possible to use a continue or return statement as early as possible and get rid of the else branch of an if-else statement. For example:

while( loopCondition ) {
    if( innerCondition ) {
        //do some stuff
    } else {
        //do other stuff
    }
}

becomes

 while( loopCondition ) {
    if( innerCondition ) {
        //do some stuff
        continue;
    }
    //do other stuff
}

and

void function() {
    if( condition ) {
        //do some stuff
    } else {
        //do other stuff
    }
}

becomes

void function() {
    if( condition ) {
        //do some stuff
        return;
    }
    //do other stuff
}

The "after" variant may be more readable if the if-else branches are long because this alteration eliminates indenting for the else branch.

Is such using of return/continue a good idea? Are there any possible maintenance or readability problems?

+15  A: 

My personal approach of choosing one is that if the body of the if part is very short (3 or 4 lines maximum), it makes sense to use the return/continue variant. If the body is long, it's harder to keep track of the control flow so I choose the else version.

As a result, normally, this approach limits the usage of return/continue style to skip some data and avoid further processing rather than process this using one of the following methods (which is better suited by if/else).

Mehrdad Afshari
+1 same here. I use early exit when checking whether there is something to do at all.
peterchen
+7  A: 

It depends a little on how long the branches are. The use of return/continue that you describe is good if the initial if check is short, and the body is long. If both if and else parts are long, I would extract them to separate functions.

I recommend reading Code Complete, it discusses things like this a lot.

kotlinski
+1 for Code Complete
Richard
also +1 for CC !
Martin K.
For completeness: as far as I remember, Code Complete argues that you don't write code for your compiler, but rather for the ones that are going to read it after you (colleagues, maintenance programmers, yourself-after-a-year).
xtofl
"Programs must be written for people to read, and only incidentally for machines to execute." - Sussman/Abelson, Structure and Interpretation of Computer Programs
John Pirie
+1  A: 

I generally use the if-return method when jumping out of a method or loop because there is nothing to be done.

If the body is longer because substantial work is being done, I suggest using if-else and maybe using #region to give blocks a sensible name and have them easily collapsable for people to study the control flow. That or make separate methods :)

Thorarin
+6  A: 

The code would be more readable if termination criteria are handled first. I always prefer, checking for conditions that require a break or return rather than those that would need lengthy code execution. I prefer:

 if (termination condn) 
      return;
 // code 
 // code

to

if (success condn)
{
  // code
  // code
}
else
 return;

This makes reading and understanding the code easier.

Rashmi Pandit
I agree, you should always test for exceptions, not the normal case. See http://stackoverflow.com/questions/114342/what-are-code-smells-what-is-the-best-way-to-correct-them/223881#223881.
hlovdal
+6  A: 

The glib answer is that it all depends.

My general feeling is that if condition is a rare, guard (e.g. check for null) or error condition then I tend to use return or continue

If it's an expected case then I tend to use your first approach.

Notice, however, that I said "tend". The boundary between these to conditions is vague and subject to change depending on the project and who I'm working with.

ChrisF
+2  A: 

I usually prefer

while( loopCondition ) {
    if( innerCondition ) {
        DoStuff();
    } else {
        DoOtherStuff(); 
    }
}

continue can be hard to follow if the length of DoStuff passed the 1-2 line threshold (and its fairly easy to miss the intention). This seems like a good opportunity to refactor the logic into some smaller methods.

Sam Saffron
The if/else { } aren't needed in this case. They are bloating.
Martin K.
+1  A: 

The compiler will almost certainly generate the same code. Even if it didn't, the difference will be probably irrelevant. Hence, the relevant argument is certainly how people would read it.

Therefore the question is how similar "//do some stuff" and "do other stuff" are. If they are conceptually similar, use if/else. If they're conceptually different, use continue/return.

MSalters
+1  A: 

Do not sacrifice readability for premature optimization.

For example:

void function() {
    if( condition ) {
        //do some stuff
    } else {
        //do other stuff
    }
}

is in most cases binary equivalent to

void function() {
    if( condition ) {
        //do some stuff
        return;
    }
    //do other stuff
}

(i.e. the resulting code is probably the same). But the readability of the former is much better, because you can clearly see that the code will to either X or Y.

elmuerte
Disagree on the readability of your first, especially if the if branch is much shorter than the else (consider parameter validation).
Richard
Disagree on the different lengths argument. If any of the both parts are longer than two lines, they should be put in well-named methods anyway.
kungfoo
+2  A: 

One possible maintenance issue is that if a function has multiple returns, then it is harder to stick a breakpoint or tracing at the return when debugging. This is only rarely an issue, but when you do miss a return point it's a pain. I don't think it matters so much for continue in loops, since the loop condition and the top of the loop are both still unique.

Aside from that: what everyone else says. Do what's most readable, which depends on the relative length, importance, and likelihood of "some stuff" and "other stuff". The shorter, more trivial, and more unlikely a case is, the less disturbing it is for it to have special-case control flow.

Steve Jessop
+2  A: 

as other people said, only use return/continue if things are short.

Personally i only use continue if it is possible to write on one line like:

while( loopCondition ) {
    if( innerCondition ) continue;

    //do other stuff
}

If it's not possible to write it like this without code getting ugly, then if / else.

Joakim Elofsson
+2  A: 

For grins, I did a search across my company's codebase for "continue;" just to get an idea of where it's being used. We use if 695 times across 59 projects in one solution, roughly 1500 source files.

The main ways I see them being used are as a quick filter:

foreach (Frobozz bar in foo) {
    if (QuickFilterExclude(bar))
        continue;
    // extensive processing
}

A recovery from an expected exception:

foreach (Frobozz bar in foo) {
    Baz result = new Baz(kDefaultConfiguration);
    try {
        Baz remoteResult = boo.GetConfiguration();
    }
    catch (RemoteConnectionException) {
        continue;
    }
    result.Merge(remoteResult);
    ReportResult(result);
}

And finally in state machinery.

plinth
+2  A: 

1) Input or object state validation. Following code:

void function() {
    if( condition ) {
        //do some stuff
        return;
    }
    //do other stuff
}

is good when the condition is some requirement for function to work. It's a stage of input validation or object state validation. It then feels right to use return immediately to emphasis, that function did not run at all.

2) Multistage processing. While/continue is good when the loop pops elements from some collection and processes them in multistage manner:

while(foo = bar.getNext()) {
   if(foo.empty())
       continue;
   if(foo.alreadyProcessed())
       continue;
   // Can we take a shortcut?
   if(foo.tryProcessThingsYourself())
       continue;
   int baz = foo.getBaz();
   if(baz < 0) {
       int qux = foo.getQux();
       if(qux < 0) {
         // Error - go to next element
         continue;
       }
   }
   // Finally -- do the actual processing
   baz = baz * 2;
   foo.setBaz(baz);
}

The example shows how natural it is to use continue in scenario when series of multistage processing is done, when each processing can be interrupted by various conditions in various places.

Notice: plinth posted real-life example, which follows what 2) says.

3) General rule. I use continue and return when it corresponds with fact that something has been interrupted. I use else, when the else is part of actual processing.