262

My boss keeps mentioning nonchalantly that bad programmers use break and continue in loops.

I use them all the time because they make sense; let me show you the inspiration:

function verify(object) {
    if (object->value < 0) return false;
    if (object->value > object->max_value) return false;
    if (object->name == "") return false;
    ...
}

The point here is that first the function checks that the conditions are correct, then executes the actual functionality. IMO same applies with loops:

while (primary_condition) {
    if (loop_count > 1000) break;
    if (time_exect > 3600) break;
    if (this->data == "undefined") continue;
    if (this->skip == true) continue;
    ...
}

I think this makes it easier to read & debug; but I also don't see a downside.

37
  • 75
    No. Neither is goto. Knowing when to use them is the key. They are tools in the toolbox. You use them when they provide clear & succinct code.
    – orj
    Mar 15, 2011 at 20:41
  • 79
    I cannot voice my support for this style of coding strongly enough. Multiple levels of nested conditionals are so much worse than this approach. I'm usually not militant about coding style, but this is almost a deal-breaker for me.
    – Emil H
    Mar 16, 2011 at 5:39
  • 17
    Obviously your boss doesn't write (enough) code. If he did, he would know that all keywords (yes, even goto) are useful in some cases.
    – sakisk
    Mar 26, 2011 at 9:39
  • 77
    Bad programmers use break and continue doesn't mean that good programmers don't. Bad programmers use if and while as well.
    – mouviciel
    Nov 27, 2013 at 14:22
  • 5
    Bad programmers follow rules blindly. Worse programmers randomly either follow or don't follow rules :-( Good programmers know when to follow rules and when to ignore them. Some rules are good to prevent bad programmers from writing even worse code and are pointless to apply to good programmers.
    – gnasher729
    Aug 1, 2015 at 12:15

21 Answers 21

322

When used at the start of a block, as first checks made, they act like preconditions, so it's good.

When used in the middle of the block, with some code around, they act like hidden traps, so it's bad.

18
  • 116
    @bit-twiddler: this is a very C-ish mindset. A temporary variable can be modified later on, so a single typo 20 lines down from here could erase that carefully crafted result. An immediate return (or break, or continue) however is extremely clear: I can stop reading now because I know it can't possibly be modified further down. It's good for my little brain, really makes trudging through the code easier. Mar 17, 2011 at 19:00
  • 26
    @Matthieu I agree. Exit a block when you receive a result that satisfies the block's purpose. Mar 19, 2011 at 5:48
  • 13
    @bit-twiddler - the single-exit-point principle is separate from the single-responsibility-principle. I don't agree that checking is always separate from acting WRT the single responsibility. In fact "single responsibility" always strikes me as a subjective term. For example, in a quadratic-solver, should calculating the discriminant be a separate responsibility? Or can the whole quadratic formula be a single responsibility? I'd argue that it depends on whether you have a separate use for the discriminant - otherwise, treating it as a separate responsibility is probably excessive.
    – user8709
    Oct 6, 2011 at 8:35
  • 8
    -1. If the code is clear and concise, no break/continue statement will act as a hidden trap. Calling any code bad without seeing it first is ignorant. Feb 16, 2014 at 23:19
  • 17
    That answer is a rule of thumb, not a hard rule. It works in most cases, feel free to break it if it make sense in your context.
    – Klaim
    Jul 29, 2014 at 23:13
112

You could read Donald Knuth's 1974 paper Structured Programming with go to Statements, in which he discusses various uses of the go to that are structurally desirable. They include the equivalent of break and continue statements (many of the uses of go to in there have been developed into more limited constructs). Is your boss the type to call Knuth a bad programmer?

(The examples given interest me. Typically, break and continue are disliked by people who like one entry and one exit from any piece of code, and that sort of person also frowns on multiple return statements.)

17
  • 13
    Most of the people who like functions and procedures to have single entry and exit points grew up on Pascal. Pascal was not the first language that I learned, but it had a profound impact on how I structure code to this day. People always comment on how easy it is to read my Java code. That's because I avoid multiple exits points as well as intermixing declarations with code. I try my best to declare every local variable used in a method at the top of the method. This practice avoids code ramble by forcing me to keep methods succinct. Mar 15, 2011 at 15:37
  • 6
    Pascal also had nested functions. Just sayin'...
    – Shog9
    Mar 15, 2011 at 17:32
  • 6
    From what I remember, back in the day, the main reason that people didn't like multiple return statements in functions was because debuggers didn't handle them properly. It was a real pain to set a breakpoint at the end of a function but you never hit it because of an earlier return statement. For every compiler I use nowadays that is no longer an issue.
    – Dunk
    Mar 15, 2011 at 19:16
  • 37
    @bit-twiddler: I'm not so sure about that. I'm still using Pascal today, and I generally regard "single entry single exit," or at least the single-exit part of it, as cargo cult programming. I just consider Break, Continue and Exit as tools in my toolbox; I use them where it makes the code easier to follow, and don't use them where it would make things harder to read. Mar 15, 2011 at 21:32
  • 3
    Many have agreed that the point is to make reading the code or reasoning about it easier. When reading code, though, I usually don't follow a top-bottom pattern. I'm trying to understand something about it and not everything about it. So, if I see a while (a < 0) {...} and I think I could jump to the end of the block and expect to a >=0 to hold. A break could break that expectation.
    – manu
    Jul 13, 2016 at 21:23
61

I do not believe they are bad. The idea that they are bad comes from the days of structured programming. It is related to the notion that a function must have a single entry point and a single exit point, i. e. only one return per function.

This makes some sense if your function is long, and if you have multiple nested loops. However, your functions should be short, and you should wrap loops and their bodies into short functions of their own. Generally, forcing a function to have a single exit point can result in very convoluted logic.

If your function is very short, if you have a single loop, or at worst two nested loops, and if the loop body is very short, then it is very clear what a break or a continue does. It is also clear what multiple return statements do.

These issues are addressed in "Clean Code" by Robert C. Martin and in "Refactoring" by Martin Fowler.

6
  • 16
    "Make your functions small. Then make them smaller" -Robert C. Martin. I found that this works surprisingly well. Every time you see a block of code in a function that needs a comment explaining what it does, wrap it into a separate function with a descriptive name. Even if it is only a few lines, and even if it is only used once. This practice eliminates most of the issues with break/continue or multiple returns.
    – Dima
    Mar 15, 2011 at 15:13
  • 3
    @Mikhail: Cyclomatic complexity is generally pretty strongly correlated with SLOC, which means that the advice can be simplified to "don't write long functions". Mar 19, 2011 at 16:54
  • 4
    The idea of a single exit point is widely misinterpreted. Once upon a time, functions did not have to return their caller. They could return to some other spot. This was commonly done in assembly language. Fortran had a special construct for this; you could pass in a statement number preceded by ampersand CALL P(X, Y, &10), and in case of error, the function could pass control to that statement, instead of returning to the point of the call. Oct 6, 2011 at 0:42
  • @kevincline as seen with Lua, for instance. Dec 1, 2014 at 3:41
  • 1
    @cjsimon you got it. Not only functions should be small. Classes should be small too.
    – Dima
    Jun 1, 2018 at 20:27
52

Bad programmers speak in absolutes (just like Sith). Good programmers use the clearest solution possible (all other things being equal).

Using break and continue frequently makes code hard to follow. But if replacing them makes the code even harder to follow, then that's a bad change.

The example you gave is definitely a situation where the breaks and continues should be replaced with something more elegant.

7
  • Yeah, I exaggerated the number of conditions to provide examples of cases to exit.
    – Mikhail
    Mar 15, 2011 at 19:17
  • 16
    What is an example of the replacement code you've suggested? I thought it was a rather reasonable example of guard statements.
    – simgineer
    Aug 5, 2015 at 20:12
  • It seems to me that "the clearest solution possible" is always... possible? How could there not be a "clearest" solution? But then, I am not one for absolutes, so maybe you are right.
    – user251748
    Jun 6, 2017 at 18:29
  • @nocomprende I'm not sure what you're getting at. The "possible" here doesn't indicate that the best solution doesn't exist -- only that perfect, ultimate clarity is not a thing. It's subjective, after all. Jun 6, 2017 at 18:48
  • 1
    @MatthewRead FWIW, I like the conditions being laid out. Helper funcitons and extra variables often add more complexity than they alleviate. Also, where would you assign these? At the end of the previous iteration? What about the first iteration? What about the last iteration? Are you going to duplicate the code and add conditions? I agree with the general gist "bad programmers speak in absolutes", but I disagree with the assesment of the example.
    – Frax
    Dec 7, 2021 at 16:25
30

Most people think it's a bad idea because the behaviour isn't easily predictable. If you're reading through the code and you see while(x < 1000){} you assume it's going to run until x >= 1000...But if there are breaks in the middle, then that doesn't hold true, so you can't really trust your looping...

It's the same reason people don't like GOTO: sure, it can be used well, but it can also lead to godawful spaghetti code, where the code leaps randomly from section to section.

For myself, if I was going to do a loop that broke on more than one condition, I'd do while(x){} then toggle X to false when I needed to break out. The final result would be the same, and anyone reading through the code would know to look more closely at things that switched the value of X.

11
  • 2
    +1 very well said, and +1 (if I could do another) for the while(notDone){ } approach. Mar 15, 2011 at 15:20
  • 5
    Mikhail: The issue with break is that the final condition for the loop is never simply stated in one place. That makes it difficult to predict the post-condition after the loop. In this trivial case (>= 1000) it's not hard. Add many if-statements and different levels of nesting it it can become very, very difficult to determine the post-condition of the loop.
    – S.Lott
    Mar 15, 2011 at 15:46
  • S.Lott hit the nail squarely on the head. The expression that controls iteration should include every condition that must be met in order to continue iteration. Mar 17, 2011 at 14:19
  • 11
    Replacing break; with x=false; does not make your code more clear. You still have to search the body for that statement. And in the case of x=false; you'll have to check that it doesn't hit a x=true; further down.
    – Sjoerd
    Mar 17, 2011 at 14:57
  • 16
    When people say "I see x and I assume y, but if you do z that assumption doesn't hold" I tend to think "so don't make that stupid assumption". Many people would simplify that to "when I see while (x < 1000) I assume it will run 1000 times". Well, there's many reasons why that's false, even if x is initially zero. For example, who says x is incremented precisely once during the loop, and never modified in any other way? Even for your own assumption, just because something sets x >= 1000 doesn't mean the loop will end - it may be set back in range before the condition gets checked.
    – user8709
    Oct 6, 2011 at 9:57
30

Yes you can [re]write programs without break statements (or returns from the middle of loops, which do the same thing). But you may have to introduce additional variables and/or code duplication both of which typically make the program harder to understand. Pascal (the programming language) was very bad especially for beginner programmers for that reason. Your boss basically wants you to program in Pascal's control structures. If Linus Torvalds were in your shoes, he would probably show your boss the middle finger!

There's a computer science result called the Kosaraju's hierarchy of control structures, which dates back to 1973 and which is mentioned in Knuth's (more) famous paper on gotos from 1974. (This paper of Knuth was already recommended above by David Thornley, by the way.) What S. Rao Kosaraju proved in 1973 is that it's not possible to rewrite all programs that have multi-level breaks of depth n into programs with break depth less than n without introducing extra variables. But let's say that's just a purely theoretical result. (Just add a few extra variables?! Surely you can do that to please your boss...)

What's far more important from a software engineering perspective is a more recent, 1995 paper by Eric S. Roberts titled Loop Exits and Structured Programming: Reopening the Debate (http://cs.stanford.edu/people/eroberts/papers/SIGCSE-1995/LoopExits.pdf). Roberts summarizes several empirical studies conducted by others before him. For example, when a group of CS101-type students were asked to write code for a function implementing a sequential search in an array, the author of the study said the following about those students who used a break/return/goto to exit the from the sequential search loop when the element was found:

I have yet to find a single person who attempted a program using [this style] who produced an incorrect solution.

Roberts also says that:

Students who attempted to solve the problem without using an explicit return from the for loop fared much less well: only seven of the 42 students attempting this strategy managed to generate correct solutions. That figure represents a success rate of less than 20%.

Yes, you may be more experienced than CS101 students, but without using the break statement (or equivalently return/goto from the middle of loops), eventually you'll write code that while nominally being nicely structured is hairy enough in terms of extra logic variables and code duplication that someone, probably yourself, will put logic bugs in it while trying to follow your boss' coding style.

I'm also gonna say here that Roberts' paper is far more accessible to the average programmer, so a better first read than Knuth's. It's also shorter and covers a narrower topic. You could probably even recommend it to your boss, even if he is the management rather than the CS type.

2
  • 3
    Though structured programming was my approach for many years, in the last few have switched to entirely using explicit exits at first possible opportunity. This makes faster execution and almost eliminates logic errors that used to result in endless loops (hanging). Oct 17, 2015 at 13:25
  • This is a very detailed and pertinent answer, even after so many years. Thanks for sharing ! Sep 4, 2022 at 16:57
10

I don't consider using either of these bad practice, but using them too much within the same loop should warrant rethinking the logic being used in the loop. Use them sparingly.

1
  • :) yes, the example I provided was conceptual
    – Mikhail
    Mar 15, 2011 at 15:04
7

The example you gave doesn't need breaks nor continues:

while (primary-condition AND
       loop-count <= 1000 AND
       time-exec <= 3600) {
   when (data != "undefined" AND
           NOT skip)
      do-something-useful;
   }

My ‘problem’ with the 4 lines in your example is that they are all on the same level but they do different things: some break, some continue... You have to read each line.

In my nested approach, the more deeper you go, the more ‘useful‘ the code becomes.

But, if deep inside you'd find a reason to stop the loop (other than primary-condition), a break or return would have it's use. I'd prefer that over the use of an extra flag that is to be tested in the top-level condition. The break/return is more direct; it better states the intent than setting yet another variable.

2
  • +1 But actually your < comparisons need to be <= to match the OPs solution
    – El Ronnoco
    Mar 16, 2011 at 11:39
  • 4
    In most cases, if one is so deep that one needs to use break/return to manage flow control, one's function/method is too complex. Mar 17, 2011 at 14:30
6

The "badness" is dependent on how you use them. I typically use breaks in looping constructs ONLY when it will save me cycles that can't be saved through a refactoring of an algorithm. For instance, cycling through a collection looking for an item with a value in a specific property set to true. If all you need to know is that one of the items had this property set to true, once you achieve that result, a break is good to terminate the loop appropriately.

If using a break won't make the code specifically easier to read, shorter to run or save cycles in processing in a significant manner, then it's best not to use them. I tend to code to the "lowest common denominator" when possible to make sure that anyone who follows me can easily look at my code and figure out what's going on (I am not always successful at this). Breaks reduce that because they do introduce odd entry/exit points. Misused they can behave very much like an out of whack "goto" statement.

2
  • I agree with both points! As far as your second point - I think it's easier to follow my original post because it reads like English. If you have a combination of conditions in 1 if statement, then it's almost a deciphering to figure out what has to happen for the if to execute true.
    – Mikhail
    Mar 15, 2011 at 15:15
  • @Mikhail: The samples you provided are a little altruistic for specific realism. As I see it, those samples are clear, concise, easier to read. Most loops are not like that. Most loops have some sort of other logic they are performing and potentially much more complicated conditionals. It's in these cases where break/continue may not be the best usage because it does muddy up the logic when read. Mar 15, 2011 at 15:17
4

The essential notion comes from being able to semantically analyze your program. If you have a single entry and a single exit, the math needed to denote possible states is considerably easier than if you have to manage forking paths.

In part, this difficulty reflects out into being able to conceptually reason about your code.

Frankly, your second code is not obvious. What is it doing? Does continue 'continue', or does it 'next' the loop? I have no idea. At least your first example is clear.

8
  • When I work in a project that manager obligate to use them, I had to use a flowchart to remember its use, and the several exit paths, did make more confusing th code...
    – umlcat
    Mar 15, 2011 at 18:15
  • your "Frankly" comment is syntactic -- "next" is a perl thing; normal languages use "continue" to mean "skip this loop"
    – Mikhail
    Mar 15, 2011 at 18:42
  • 1
    @Mik, maybe "skip this iteration" would be a better description. Yours truly, Dr. I. M. Pedantic Mar 15, 2011 at 19:05
  • @Mikhail: Sure. But when one works in lots of languages, it can lead to errors when the syntax isn't common between languages. Mar 15, 2011 at 19:59
  • But math is not programming. Code is more expressive than math. I get that single-entry/single-exit may make flowcharts look nicer but at what expense (Ie. where break/return can make code perform better)? Mar 19, 2011 at 7:34
4

Absolutely not... Yes the use of goto is bad because it deteriorates the structure of your program and also it is very difficult to understand the control flow.

But use of statements like break and continue are absolutely necessary these days and not considered as bad programming practice at all.

And also not that difficult to understand the control flow in use of break and continue. In constructs like switch the break statement is absolutely necessary.

3
  • 2
    I haven't used "continue" since I first learned C in 1981. It is an unnecessary language feature, as the code that is bypassed by the continue statement can be wrapped by a conditional control statement. Mar 15, 2011 at 15:24
  • 16
    I prefer to use continue in those cases since it makes sure that my code doesn't become arrow code. I hate arrow code more than goto type statements. I also read it as, "if this statement is true, skip the rest of this loop and continue with the next iteration." Very useful when it's at the very beginning of a for loop (less useful in while loops).
    – jsternberg
    Mar 15, 2011 at 15:48
  • @jsternberg For for the win! :-)
    – Notinlist
    Sep 26, 2012 at 12:24
3

I disagree with your boss. There are proper places for break and continue to be used. In fact the reason that execeptions and exception handling were introduced to modern programming languages is that you can't solve every problem using just structured techniques.

On a side note I don't want to start a religious discussion here but you could restructure your code to be even more readable like this:

while (primary_condition) {
    if (loop_count > 1000) || (time_exect > 3600) {
        break;
    } else if ( ( this->data != "undefined") && ( !this->skip ) ) {
       ... // where the real work of the loop happens
    }
}

On another side note

I personally dislike the use of ( flag == true ) in conditionals because if the variable is a boolean already, then you are introducing an additional comparison that needs to happen when the value of the boolean has the answer you want - unless of course you are certain that your compiler will optimize that extra comparison away.

3
  • I have waffled on this question for years. Your way ( 'if ( flag ) {...}' ) is a lot more terse and maybe it looks more 'professional' or 'expert'. But, ya' know, it often means that a reader/maintainer has to interrupt herself briefly to recall what the construct means; and to be sure of the sense of the test. Currently, I am using 'if ( flag == true) { ... }' just because it seems to be better documentation. Next month? Quien sabe? Mar 15, 2011 at 19:02
  • 2
    @Pete - The term is not terse but elegant. You can waffle all you want, but if you are worried that the reader/maintainer doesn't understand what a boolean is or what the terse/elegant terminology means is then maybe you better hire some smarter maintainers ;-) Mar 15, 2011 at 19:30
  • @Pete, I also stand by my statement about the generated code. You are doing one more compare by comparing a flag to a constant value before evaluating boolean value of the expression. Why make it harder than it has to be, the flag variable already has the value you want! Mar 15, 2011 at 19:33
3

I would replace your second code snippet with

while (primary_condition && (loop_count <= 1000 && time_exect <= 3600)) {
    if (this->data != "undefined" && this->skip != true) {
        ..
    }
}

not for any reasons of terseness - I actually think this is easier to read and for someone to understand what is going on. Generally speaking the conditions for your loops should be contained purely within those loop conditions not littered throughout the body. However there are some situations where break and continue can help readability. break moreso than continue I might add :D

3
  • WHile I disagree with, "I actually think this is easier to read" this does accomplish the exact same purpose as the code above. I've never really thought of 'break' as a short-circuit operator until now but it makes perfect sense. As for,"Generally speaking the conditions for your loops should be contained purely within those loop conditions", what do you do when you're processing a foreach loop since there's really no way to insert conditional logic in the loop definition? Mar 26, 2011 at 8:56
  • @Evan The condition is not applicable to a foreach loop as this will just iterate every item in a collection. A for loop is similar in that it should not have a conditional end point. If you do need a conditional end point then you need to use a while loop.
    – El Ronnoco
    Jul 25, 2011 at 13:06
  • 1
    @Evan I do see your point though - ie 'what if you need to break out of a foreach loop?' - Well, there should only be one break maximum in my opinion from the loop.
    – El Ronnoco
    Jul 25, 2011 at 13:10
3

I agree with your boss. They are bad because they produce methods with high cyclomatic complexity. Such methods are difficult to read and difficult to test. Fortunately there's an easy solution. Extract the loop body into a separate method, where the "continue" becomes "return". "Return" is better because after "return" it's over -- there's no worries about the local state.

For "break" extract the loop itself into a separate method, replacing "break" with "return".

If the extracted methods require a large number of arguments, that's an indication to extract a class -- either collect them into a context object.

3
  • 1
    Check the quote of Code Complete below. Not using a continue and replacing it with a nested IF increments the cyclomatic complexity. Just the opposite of your argument, May 24 at 9:43
  • Where did I say anything in favor of nested IF statements? May 26 at 4:23
  • You said "They are bad because they produce methods with high cyclomatic complexity" referring to break/continue. May 26 at 18:56
1

I will just quote from Code Complete:

Use continue for tests at the top of the loop. A good use of continue is for moving execution past the body of the loop after testing a condition at the top. For example, if the loop reads records, discards records of one kind, and processes records of another kind you could put a test like this at the top of the loop. Using continue in this way lets you avoid an if test that would effectively indent the entire body of the loop. If on the other hand, the continue occurs toward the middle or end of the loop, use and if instead.

0

I think it's only a problem when nested deeply inside multiple loops. It's hard to know which loop you are breaking to. It might be difficult to follow a continue also, but I think the real pain comes from breaks - the logic can be difficult to follow.

6
  • 2
    Actually, it's easy to see if you indent properly, have the semantics of those statements internalized and aren't too sleepy.
    – user7043
    Mar 15, 2011 at 14:56
  • @delnan - that's a lot of assumptions ;) Mar 15, 2011 at 14:56
  • Well, #1 is required for serious programming anyway, #2 is to be expected from everyone called programmer, and #3 is quite useful in general ;)
    – user7043
    Mar 15, 2011 at 14:57
  • Some languages (only scripting that I know) support break 2; for others, i guess temporary bool flags are used
    – Mikhail
    Mar 15, 2011 at 15:03
  • @Mikhail or even goto...
    – Gipsy King
    Mar 15, 2011 at 15:37
0

As long as they're not used as disguised goto like in the following example :

do
{
      if (foo)
      {
             /*** code ***/
             break;
      }

      if (bar)
      {
             /*** code ***/
             break;
      }
} while (0);

I'm fine with them. (Example seen in production code, meh)

3
  • Would you recommend for cases like these to create functions?
    – Mikhail
    Mar 28, 2011 at 17:03
  • Yes and if not possible, a plain goto. When I see a do, I think repetition, not context to simulate jump.
    – SuperBloup
    Mar 29, 2011 at 8:18
  • oh I agree, i was just asking how you'd do it :) Computer scientists do it repeatedly
    – Mikhail
    Mar 29, 2011 at 14:09
0

I don't like either of these styles. Here's what I would prefer:

function verify(object)
{
    if not (object->value < 0) 
       and not(object->value > object->max_value)
       and not(object->name == "") 
       {
         do somethign important
       }
    else return false; //probably not necessary since this function doesn't even seem to be defined to return anything...?
}

I really don't like using return to abort a function. It feels like an abuse of return.

Using break also is not always clear to read.

Better yet might be:

notdone := primarycondition    
while (notDone)
{
    if (loop_count > 1000) or (time_exect > 3600)
    {
       notDone := false; 
    }
    else
    { 
        skipCurrentIteration := (this->data == "undefined") or (this->skip == true) 

        if not skipCurrentIteration
        {
           do something
        } 
        ...
    }
}

less nesting and the complex conditions are refactored into variables (in a real program you'd have to have better names, obviously...)

(All above code is pseudo-code)

15
  • 13
    You would really prefer 3 levels of nesting over what I typed above?
    – Mikhail
    Mar 15, 2011 at 15:02
  • @Mikhail: Yes, or I'd assign the result of the condition to a variable. I find it much easier to understand than the logic of break and continue. Abnormally ending a loop just feels weird and I don't like it. Mar 15, 2011 at 15:05
  • 1
    Ironically, you've misread my conditions. continue means skip the functionality go to the next loop; not "continue with execution"
    – Mikhail
    Mar 15, 2011 at 15:19
  • @Mikhail: Ah. I don't use it often and when I read it, I get confused by the meaning. Another reason I don't like it. :P Give me a minute to update... Mar 15, 2011 at 15:27
  • 8
    Too much nesting destroys readability. And sometimes, avoiding the break/continue introduces the necessity of inverting your logic on your conditional tests, which can lead to misinterpretation of what your code is doing -- I'm just sayin' Mar 15, 2011 at 18:45
0

No. It's a way to solve a problem, and there are other ways to solve it.

Many current mainstream languages (Java, .NET (C# + VB), PHP, write your own) use "break" and "continue" to skip loops. They both "structured goto (s)" sentences.

Without them:

String myKey = "mars";

int i = 0; bool found = false;
while ((i < MyList.Count) && (not found)) {
  found = (MyList[i].key == myKey);
  i++;   
}
if (found)
  ShowMessage("Key is " + i.toString());
else
  ShowMessage("Not found.");

With them:

String myKey = "mars";

for (i = 0; i < MyList.Count; i++) {
  if (MyList[i].key == myKey)
    break;
}
ShowMessage("Key is " + i.toString());

Note that, "break" and "continue" code is shorter, and usually turns "while" sentences into "for" or "foreach" sentences.

Both cases are a matter of coding style. I prefer not to used them, because the verbose style allows me to have more control of the code.

I actually, work in some projects, where it was mandatory to use those sentences.

Some developers may think they are not necesarilly, but hypothetical, if we had to remove them, we have to remove "while" and "do while" ("repeat until", you pascal guys) also ;-)

Conclusion, even if I prefer not to use them, I think its an option, not a bad programming practice.

5
  • Sorry to be picky, but your second example is missing the output for when the key is not found (so of course it looks that much shorter). Mar 15, 2011 at 18:10
  • 2
    not to mention that the first example only works if the key is the last one in the list.
    – Mikhail
    Mar 15, 2011 at 18:41
  • @FrustratedWithFormsDesigner EXACTLY. I put on purpouse to denote why is preferable that method ;-)
    – umlcat
    Mar 15, 2011 at 23:09
  • however, you have two routines with different semantics; therefore, they are not logically equivalent. Mar 17, 2011 at 14:48
  • 2
    your second example has two bugs, one syntactic and one logical. 1. It won't compile because the iterator isn't declared outside the scope of the for loop (therefore isn't available in the string output). 2. Even if the iterator was declared outside of the loop, if the key isn't found in the collection, the string output would print the key of the last item in the list. Mar 19, 2011 at 7:40
0

I'm not against continue and break in principle, but I think they are very low-level constructs that very often can be replaced by something even better.

I'm using C# as an example here, consider the case of wanting to iterate over a collection, but we only want the elements that fulfil some predicate, and we don't want to do any more than a maximum of 100 iterations.

for (var i = 0; i < collection.Count; i++)
{
    if (!Predicate(item)) continue;
    if (i >= 100) break; // at first I used a > here which is a bug. another good thing about the more declarative style!

    DoStuff(item);
}

This looks REASONABLY clean. It's not very hard to understand. I think it would stand to gain a lot from being more declarative though. Compare it to the following:

foreach (var item in collection.Where(Predicate).Take(100))
    DoStuff(item);

Maybe the Where and Take calls shouldn't even be in this method. Maybe this filtering should be done BEFORE the collection is passed to this method. Anyway, by moving away from low-level stuff and focusing more on the actual business logic, it becomes more clear what we're ACTUALLY interested in. It becomes easier to separate our code into cohesive modules that adhere more to good design practices and so on.

Low-level stuff will still exist in some parts of the code, but we want to hide this as much as possible, because it takes mental energy that we could be using to reason about the business problems instead.

-1

Code Complete has a nice section about using goto and multiple returns from routine or loop.

In general it's not bad practice. break or continue tell exactly what happens next. And I agree with this.

Steve McConnell (author of Code Complete) uses almost the same examples as you to show advantages of using various goto statements.

However overuse break or continue could lead to complex and unmaintainable software.

Not the answer you're looking for? Browse other questions tagged or ask your own question.