3

Suppose I am doing an if-else clause inside a for loop. I like to structure it as

for (...)
    if (...)
        // (part A)
        continue;
    //(part B)

rather than

for (...)
    if (...)
        // (part A)
    else
        (part B)

but I can imagine that coders might have strong opinions on this. Is there a standard? Apologies if this has been asked; I couldn't find it.

Eric Auld
  • 141
  • 4
  • 5
    Closely related: [Which is a better pattern (coding style) for validating arguments - hurdle (barrier) or fence?](https://softwareengineering.stackexchange.com/q/255817/60357) (using an early `continue` in a loop is quite similar to an early return in a function. I'm 100% team pro continue, anti nested clauses) – amon Mar 10 '19 at 22:50
  • 1
    Side note, slightly off-topic, but read [Code Complete 2](https://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670/ref=sr_1_1?keywords=code+complete+2). There are discussions about how to write an if, how to throw an exception, how to write a proper for loop. The **best** book about programming I've ever read. – Machado Mar 11 '19 at 14:17
  • 2
    Disagreeing with the two answers slightly, in the specific case of **inside a loop**, I'd generally favor `if/else` over `continue.` **return** is cognitively simple - nothing left to consider (other than, perhaps, cleanup in a `finally` clause). **continue** , by contrast, requires more thought: carry local variables forward, look for the end of the loop, etc... – user949300 Mar 11 '19 at 17:27

3 Answers3

9

No, there is no "standard." That's why you can't find it. The loop structure you use will depend entirely on your specific program logic and requirements. Use continue when your program logic dictates that you should abandon a loop iteration early.

In general, you would use continue or break when you determine that your work is done in that loop or loop iteration. For example, a search loop would break when the item being searched is actually found, since any further work in that loop only serves to chew up clock cycles unnecessarily.

Questions that ask "is there a 'standard' for [some ordinary piece of work]" often labor under the incorrect assumption that there is one right/true/correct/best way to do everything. There isn't. Even if there were, it won't be the "correct" way five years from now, or maybe even five minutes from now.

Software development is not a pattern-matching exercise. Instead of asking yourself what is the "standard" way to do something, ask yourself if it suits your purpose.

Robert Harvey
  • 198,589
  • 55
  • 464
  • 673
  • I see what you mean. But to play devil's advocate, isn't part of the *purpose* of any code to be accessible to people who might read it, and aren't there a lot of considerations for that besides merely what is logical and efficient? E.g. it is just as logical and efficient to drive on the left side of the road. – Eric Auld Mar 10 '19 at 22:57
  • We have a name for that line of thinking. It's called a "non-sequitur." – Robert Harvey Mar 10 '19 at 22:58
  • 1
    I understand what a non sequitur is, but I'm not sure I understand what you mean. If you're just pointing out that I don't understand, you're right, and that's why I'm asking. I always seem to get snarked on this site. – Eric Auld Mar 10 '19 at 23:00
  • 1
    Have a look [here](https://meta.stackexchange.com/a/142354/102937). I would note that a previous version of that answer was quite a bit snarkier than the current, user-friendly, sanitized version. – Robert Harvey Mar 10 '19 at 23:02
  • 3
    Also, note that, in the back recesses of your mind, you might be vaguely recalling in a blog post somewhere someone cogitating over the evils of "early exit." That idea originated back in the C days, before the widespread use of garbage collection, when you still had to allocate memory yourself and make sure that it was properly disposed. "One entry point, one exit point" facilitates proper memory allocation and disposal. It's an idea that has been obsolete for years (unless, of course, you happen to be working with C), but people still dredge it up occasionally. – Robert Harvey Mar 10 '19 at 23:07
  • @RobertHarvey In a readability sense, one entry point, one exit point is still a good general guideline. But of course it is just that, a guideline. It's not going to cause me readability issues unless you've got deeply nested loops and if statements containing "continue", "return", or "break". – Neil Mar 11 '19 at 13:37
6

Restating the context

Apologies if this has been asked; I couldn't find it.

That might have to do with the fact that you're thinking about loops, where this is not really about loops. In both your examples, the loop part (for (...)) is exactly the same, while the difference is only inside that loop. Just to show more clearly what I mean, lets move the relevant bits out of the loop (plus adding brackets to make more clear what belongs to what):

// The loop ===
for (...) {
    DoThing();
}


// Option A ===
void DoThing(){
    if (...){
        // (part A)
        return; // "continue;" becomes "return;"
    }
    // (part B)
}


// Option B ===
void DoThing(){
    if (...){
        // (part A)
    }
    else {
        // (part B)
    }
}

So what your question comes down to is "early return vs. else".

Answering the question in that context

Is there a standard?

Well, there is not a standard. There are several. The two options you presented are 2 different standards. You'd think that was it, but there's advocates for a third one, else AND return:

int max(int a, int b)
{
    if (a > b)
        return a;
    else
        return b;
}

Those are all valid, they all work.

What to do?

My advice would be to favour early returns. It can greatly reduce visual clutter and for that reason seems to be preferred by the majority of programmers here on software engineering as well as on stackoverflow (1, 2). There are also numerous blogs etc. advocating that style (1, 2, 3), but honestly, they're all just reiterating the same point.

Guidelines, not rules

Even if you say for yourself "I will use early returns", every "rule" in software engineering comes with the implicit adage "...except if you have a good reason (not) to do that."

For example, for small statements it's often easier to read

if(condition) DoThingA();
else DoThingB();

than

if(condition){
    DoThingA();
    return;
}
DoThingB();

So, why not just use else then? It's better to not restrict yourself here.

R. Schmitz
  • 2,608
  • 1
  • 16
  • 28
  • 1
    That's the great thing about standards... there are [so many of them](https://imgs.xkcd.com/comics/standards.png). – Robert Harvey Mar 11 '19 at 15:22
  • 1
    Thanks for adding "else after return". In the Javascript callback hell world, that's a great style to use. – user949300 Mar 11 '19 at 17:23
  • 1
    @user949300 I personally don't like it much because it also creates an indent, but I'm also not that fond of dynamic languages as a whole. But what you said, yeah, it makes sense again in that situation. – R. Schmitz Mar 11 '19 at 18:14
1

There are many ways to achieve the same result using different language features. Then you should choose the version that most clearly shows your intent - it's all about readability.

Using "else" vs. early-abort

Use else to express "There are two similarly-ranked alternatives".

If the two branches created by an if condition are comparable in rank / probability, I prefer to have both indented (placed in its own sub-block), using else in-between.

If one branch is a special situation allowing an early abort of the main control flow, and the other branch is the normal continuation, then I prefer an early-abort keyword like break, return or continue, depending on the context. This way, the normal continuation stays on the same indentation level as the code before the condition, indicating that it's the normal sequence of steps.

Early-abort using "return"

Use return to express "I'm finished (early) with this function".

This one is very popular, because it's easily understood. If you see the return keyword, you know that this leaves the currently-executing method. You don't have to search for the place where to continue. I use this quite often.

Early-abort using "break"

Use break to express "I'm finished (early) with this loop".

This leaves the currently-executing loop. It's not that easily readable: you have to look for the next enclosing for / while / do-while loop, and you should keep in mind that none of the looping elements (e.g. i<10 or i++) is executed any more (ok, you'd expect that).

Early-abort using a labeled "break" (Java)

Use break label to express "I'm finished (early) with the named block".

This is valid only inside a block with that label. There aren't many situations where you'd need that, so it's quite unusual to such a degre that many developers don't even know that this construct exists. To understand the code, you have to search backwards for the label, and then skip the block forward to reach the continuation point.

Early-abort using "continue"

Use continue to express "I want to immediately jump to the next iteration".

This leaves the currently-executing loop iteration. It's not easily readable: you have to look for the next enclosing for / while / do-while loop, and you should keep in mind that the looping elements (e.g. i++ and i<10) are executed before the next iteration starts. I've rarely used that.

So, choose the one that best expresses the intent of the conditional situation.

Ralf Kleberhoff
  • 5,891
  • 15
  • 19