259

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.

Stevoisiak
  • 1,264
  • 1
  • 11
  • 20
Mikhail
  • 367
  • 2
  • 5
  • 10
  • 2
    Doesn't take much to forget which one does what. –  Mar 15 '11 at 16:02
  • 74
    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 '11 at 20:41
  • 2
    That type of coding can lead to what I like to refer to as "code ramble." Code ramble is what occurs when one tries to include the functionality of multiple functions within one function. Code ramble is almost a given in Java because the language allows for and its libraries promote the intermixing of code and data declarations in methods. One must be very vigilant to avoid coding several hundred line, poorly-factored methods. My upper bound for a method to sixty printed lines. That count includes blank lines. – bit-twiddler Mar 15 '11 at 22:35
  • 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 '11 at 05:39
  • 16
    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 '11 at 09:39
  • 1
    He didn't call them useless... just called them bad practice – Mikhail Mar 28 '11 at 17:04
  • I would add to Klaim's answer: ideally (and particularly if they get long) your preconditions should be in a local function of its own, so then you do not mix break and continue :) – Job Oct 06 '11 at 02:07
  • 2
    Your question seems to suggest that `break` may/maynot be bad practice compared with `return`. Those `return` statements are alternative exit-points for the loop too - and also alternative exit-points for the whole function. There is a time and a place, of course, but the thing to watch out for is having non-obvious exit points (a weaker but pragmatic version of the single-exit-point rule). Personally, I'd be nervous about mixing `continue` in with a mess of `break` exit points, though - the fact that one or two of the exit-points behave differently isn't necessarily obvious at a glance. –  Oct 06 '11 at 08:10
  • @Thorbjørn - I never thought about `continue` being a sensible keyword for `continue after the end of the loop` until I tried to write a comment calling you an idiot. Damn! That said, I don't see how `break` can be misinterpreted as `go back to the top of the loop`. –  Oct 06 '11 at 08:20
  • @Thorbjørn - Continue = skip to the next iteration of the loop, break = stop the loop... right? – Anonymous Oct 06 '11 at 09:48
  • 1
    just because bad programmers use it, doesn't mean there can be no legitimate uses as well :) – jwenting Oct 06 '11 at 11:39
  • @ThomasX no need to be rude. I wondered - have you tried maintaining such code written by _others_ yet? –  Oct 06 '11 at 13:31
  • @Thorbjørn - I have, and rarely had a problem with it, but I've mostly (not always) had to maintain code where those were used sensibly. One thing that sticks out in memory is that for a long time I ignored and forgot about `continue` (there's no such thing in Pascal) - until I found it in someone elses code that I was maintaining. I remember it because the confusion was momentary, and because it was an "I'm such an idiot - why haven't I been doing this myself?" moment. –  Oct 07 '11 at 06:00
  • 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 '13 at 14:22
  • 1
    I would definately change your second example to include the loop_count and time_exect to be inside the where-clause instead of having their own break. – Pieter B Dec 16 '13 at 14:35
  • @PieterB, what where-clause? – Mikhail Dec 19 '13 at 06:50
  • 1
    @Mikhail sorry, I meant having them in the "while" condition, not where. while (primary_condition && (loop_count > 1000)&& time_exect > 3600) ) { – Pieter B Dec 19 '13 at 07:56
  • 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 01 '15 at 12:15
  • 1
    The break-conditions can go together in the while-condition, the continue-conditions can be inversed into proper nested ifs that will only execute if the condition is right. I tend to only execute code in situations that can be trusted and that is INSIDE an if-statement where you just evaluated the proper conditions. However, if you only write some breaks or continues at the top, *who knows* you might have forgotten about some extreme situation where your code still will end up because you didn't include a break or continue for that specific situation! My advice: only execute when sure. – klaar Apr 28 '16 at 14:16
  • Good programmers go to single-exit. Bad programmers goto everywhere. –  Jun 08 '17 at 13:44
  • @klaar Inside a loop, putting everything inside an `if(condition){}` is 100% the same as having `if(!condition) continue;` at the beginning. You're still running the code "where you just evaluated the proper conditions". Forgetting an edge case will happen just the same way for both ways. However, the latter saves you up to 2 lines and 1 indent. – R. Schmitz Oct 20 '17 at 13:48
  • Yes, I was wrong about that. Although having my code wrapped in an `if` or `else` statement gives me a visual reminder that this code is executed conditionally, while in _your_ code you have to keep that fact in mind, but if you don't and you forget, then you're entering the Danger Zone. – klaar Oct 21 '17 at 14:39
  • Either case, it's silly to have to put so many condition checks in your code. It's far better to delegate that and have a single "should I or should I not" condition to which that combination boils down. – klaar Oct 21 '17 at 14:45
  • If your boss says something like "bad programmers" it is a good reason to change the boss. We call such people "sofa experts". – Kibernetik Jul 15 '19 at 07:43
  • Apparently this is also marked as a minor Sonar issue, but they don't provide an alternative. – ACV Aug 10 '20 at 10:48
  • When you tell someone to go buy some tomatoes, do you speak in negatives all the time? "If there's no money, don't do anything. Otherwise, if the store is closed, don't do anything. Otherwise, if there are no tomatoes in the store, don't do anything. Otherwise..." – Martin Oct 31 '22 at 13:29
  • @Martin comparing to real life is a bit silly because all of those are assumed by an adult human. But if I tell my 5 year old to buy tomatoes I will definitely explain what to do if there are no tomatoes or if the store is closed etc – Mikhail Nov 01 '22 at 14:36
  • @Mikhail if you were to explain it to a child, would you speak in negatives? – Martin Nov 01 '22 at 15:11
  • I don't think I understand what you're trying to say, @Martin. "If there aren't any tomatoes then buy cucumbers" yes I would say that. – Mikhail Nov 02 '22 at 16:35
  • @Mikhail you're missing the point. The point is that the person consuming the information (the child you're sending to the store, or the person reading your code) doesn't care about the failure cases. Making statements in negative form, with the error handling intertwined with the "good" code, it's extremely confusing and counter-intuitive. It's even worse when it starts affecting the flow of loops, since now I need to go through the entire body of the loop to figure what the exit condition is. `continue` is the worst of all; it acts like a miniature `goto` within the loop. – Martin Nov 02 '22 at 16:59
  • I might add that the only acceptable case for such early bailouts is exception throwing, since in that case the error handling happens through a different channel than regular return codes. So while having multiple return statements in a function is bad, it makes sense to have multiple throws. As long, of course, as they're handled as the "else" cases, at the bottom of the function with the rest of the uninteresting code. – Martin Nov 02 '22 at 17:04
  • You're saying exceptions are better than returns. At best that's a preference, and at worst - you're disagreeing that exceptions should be actually exceptional situations, not the norm. To make your case stronger can you provide an example with multiple conditions like I have above, but in the style that you'd prefer? – Mikhail Nov 03 '22 at 18:08
  • @Mikhail Unless you're in a hard real-time environment, exceptions _are_ always better than returns for error reporting. Hell, C++'s entire existence is justified by using exceptions and RAII for error handling. In your first example, I'd throw an exception if e.g. `value < 0` is an _error condition_, which shouldn't happen unless someone messed up at some point. If `value < 0` is an acceptable case which you just want to ignore, using exceptions is wrong. In that case, I'd just restructure the function to perform all the checks in a single `if` (or better yet, by calling a function). – Martin Nov 10 '22 at 13:36
  • @Mikhail And obviously, it would be something like `success = (value >= 0 && value <= max_value && ...); if (success) { success = ... }`, with a single `return success` at the end, outside the `if`. Sorry for the bad indentation, looks like this comment box doesn't allow for blank lines, etc. – Martin Nov 10 '22 at 13:39
  • Seems like a stylistic preference, and in my opinion it's hard to quickly grok when reading someone else's code. Comment from Matthieu on the accepted answer says it well. – Mikhail Nov 14 '22 at 02:56
  • @Mikhail it's a "stylistic preference" as much as `goto`, `longjmp`, and other such constructs are. I don't see how thinking in negatives all the time is clearer than following a simple if-else logic, but I guess it's the same as with conventional current: sometimes the wrong way of thinking is so ingrained in the industry than trying to fix it is a hopeless endeavor. – Martin Nov 18 '22 at 09:41
  • 1
    I disagree with your boss. `break` and `continue` are perfectly legitimate and concise way of exiting from a loop. Makes the code clearer than compounding `if's`. – user7195 Jan 02 '23 at 22:26

21 Answers21

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.

Klaim
  • 14,832
  • 3
  • 49
  • 62
  • 3
    Personally, I'd prefer an if-statement to handle pre-conditions. `if(dataIsOK) { someSomething(data) }` is clearer, IMO. – FrustratedWithFormsDesigner Mar 15 '11 at 15:22
  • For me it depends on how much conditions and different behaviours on each condition you have to check. If there is one condition, one behaviour, yes it's easier to just imbricate in a if. If however you have several conditions with return or breaks or continue or other special behaviours, I prefer short and clear statements (like assertions but in a non-error way). – Klaim Mar 15 '11 at 15:40
  • @FrustratedWithFormsDesigner: if-statements are limited when you want to perform some action like logging, using breaks you can log more detailed ( if(!conditionA){ log("Condition A failed"); break;} ). – Inca Mar 15 '11 at 18:51
  • 6
    @Klaim: It can be argued that any routine that has several exit points is a poorly-factored routine. A properly factored routine should do one thing and one thing only. – bit-twiddler Mar 16 '11 at 13:45
  • 4
    @bit-twiddler: I agree on the principle, but the purpose of a routine isn't directly related to it's behaviour. Doing one thing might result in different results, that might, or not, have been generated by different instruction flows. As far as it is correct and, indeed, does only one thing, and does it well, then the way it's written inside is a totally orthogonal problem. I believe that's why we like to enforce abstraction through encapsulation (hidding the guts of the process), polymorphism (hidding wich implemenation will be called), generic programming and other abstraction techniques. – Klaim Mar 16 '11 at 13:55
  • 1
    @Klaim: I have been writing code for over thirty years and have never used the continue statement or multiple exit points in my code. These language features are frankly not needed in properly structure logic. The only time that I use break is in case statements. Furthermore, multiple results can be handled by assigning a result to a local "result" variable and returning that variable at the end of the routine. One should not code for oneself. One should code for the poor sole who is going to have maintain the code in the future without the benefit of the original design rational. – bit-twiddler Mar 16 '11 at 14:08
  • 3
    @bit-twiddler: I agree that we could code the same algorithms without those features. I don't agree on the unusefulness (is it correct english) of having some shortcuts to do the same (clearly return, continue and break are just shortcuts). I believe syntactically permissive languages are more prone to allow those shortcuts because they rely a lot on the programmer's expertise/experience to use them where it's reasonnable. I also believe that not providing them is not a real problem. – Klaim Mar 16 '11 at 14:28
  • 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. – Matthieu M. Mar 17 '11 at 19:00
  • 26
    @Matthieu I agree. Exit a block when you receive a result that satisfies the block's purpose. – Evan Plaice Mar 19 '11 at 05: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. –  Oct 06 '11 at 08: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. – Nikola Malešević Feb 16 '14 at 23:19
  • 5
    I'm afraid I'm gonig to have to agree with the others. Well structured code can have a break other then at the top. For instance what if you can't do your error checking immediately? You have to fist derive foo before you can check rather foo is valid to decide rather to continue/break. it can still be clear if you check if foo is your desired value and break as soon as foo is calculated, even if that is in the middle of your code – dsollen Jul 22 '14 at 22:50
  • 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 '14 at 23:13
  • 3
    I use them as often as possible. There is beauty in their aggressive GTFO, no hidden meaning, no possibility that your control variable lies. Moreover, the use of this programming style keeps the code very flat, making easy to spot these statements. If you write short functions (and you should), you will never run into trouble. – bgusach Apr 07 '16 at 18:45
  • @bgusach if your functions are short enough, you might as well handle the happy path first and get rid of any `break` and `continue`s. The code is more readable that way, too. – Martin Nov 02 '22 at 14:03
  • @Martin, while I still agree with what I wrote 6 years ago (TBH, not very often the case), I agree with you as well... it's stupid to have a loop with a "sad path" check plus a continue, and then the happy path. In such case just handle the happy one. Programming is closer to alchemy than science. Rules of thumb are often powerful, but it rarely hurts to use some common sense. – bgusach Nov 02 '22 at 14:59
  • @bgusach sure, and common sense dictates that we should always handle the happy path first. If your function gets too nested, split off another one. – Martin Nov 02 '22 at 15:06
  • @Martin `and common sense dictates that we should always handle the happy path first`, well I'm afraid our common senses differ a little :). Mine tells me to do whatever is easiest to understand, and more often than not it's handling the error cases first (but not always). – bgusach Nov 02 '22 at 15:36
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.)

David Thornley
  • 20,238
  • 2
  • 55
  • 82
  • 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. – bit-twiddler Mar 15 '11 at 15:37
  • 6
    Pascal also had nested functions. Just sayin'... – Shog9 Mar 15 '11 at 17:32
  • Pascal, C, and Java are just children of Algol style programming languages. – Zeke Hansell Mar 15 '11 at 18:31
  • 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 '11 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. – Mason Wheeler Mar 15 '11 at 21:32
  • 1
    @Zeke Hansell: I concur with your assessment that most of the languages in use today are from the Algol family. However, Wirth took Algol in a different direction when he created Pascal. His goal was to design a teaching language that enforced good programming practices. Unlike Pascal, C is not really a direct descendant of Algol. It is a descendant of CPL, which was influenced by Algol. Ada is another Algol derivative, but it is more strongly-typed than Pascal. Let's not forget PL/SQL. Server-side PL/SQL is yet another Algol-like language that uses an Ada-like syntax. – bit-twiddler Mar 15 '11 at 21:57
  • @Mason Wheeler: The dialect of Object Pascal used in Delphi bears little semblance to the language defined in the Jensen and Wirth book. Anders Hielsberg added the grammatical productions for "break" and "continue" as well as the "Exit" procedure. He also extended the grammar to allow semi-colons to be used as statement terminators as well as statement separators. In the original language definition, the terminal symbol semi-colon can only be used as a statement separator. For example, one cannot terminate the statement appearing before an "end" with a semi-colon in Jensen and Wirth Pascal. – bit-twiddler Mar 15 '11 at 22:08
  • @Mr. CRT: Nested procedures and functions are not the same thing as multiple exit points. Nested procedures and functions merely provided local scoping for functions that were not used by other functions. – bit-twiddler Mar 15 '11 at 22:14
  • @Dunk: The single entry/exit rule was introduced by Edsger Dijkstra. – bit-twiddler Mar 15 '11 at 22:23
  • @bit-twiddler: I didn't say they were the same thing. Merely that Pascal provided an alternate means of dividing up code with in a function. Pre-declaring all your variables and sticking to a single exit point isn't a big deal if you're splitting out non-trivial blocks into their own routines (whether nested or simply separate)... but if you *aren't* doing that, you end up with a mess of nested blocks and far-removed variables. – Shog9 Mar 15 '11 at 23:34
  • 1
    @Mr. CRT: One does not have that problem if one factors one's code well, and gets in the habit of passing parameters instead of relying on variable access. I rarely have a method that spans more than fifty printed lines, and that count includes white space lines that I add to make the code more readable. One thing I will say is that it is amazing to see how much one's code shrinks over the years. My code is an order of magnitude simpler than it was when I first started out in the late seventies. Back then, I used to think that complex and intricate was cool. Now, I worship at the KISS alter. – bit-twiddler Mar 16 '11 at 01:34
  • 2
    @bit-twiddler: amen to that. I'll also add that once you're down to blocks that fit easily on-screen, multiple exit points become far less troublesome. – Shog9 Mar 17 '11 at 04:52
  • @bit-twiddler: One of the worst things about Jensen & Wirth Pascal, as well as the standard, was that you couldn't necessarily have a `set of char`. I know how that started; the 6600 Wirth developed the compiler on had a 60-bit word and a size 64 character set, but it caused me trouble. – David Thornley Mar 17 '11 at 18:20
  • 2
    @bit-twiddler: I'll agree with the "short" methods: it should fit on my screen entirely, and I want to have two editors side by side so long lines are out of the equation too. However I strongly disagree with the one-entry one-exit mindset. This was done in early languages because of the necessity to clean-up manually (and thus avoided duplicating the clean-up) but with modern languages, clean-up is handled with other mechanisms (C# and Python `using`, Go `defer`, C++ RAII) which obsoletes this reason, and thus the rule. – Matthieu M. Mar 17 '11 at 19:07
  • 2
    @Mathhieu: The original purpose of one entry/one exit rule had nothing to do with cleanup. The original purpose of one entry/one exit rule was to improve program structure. The concept was introduced by Edsgar Dijkstra. Edsgar is the father of "gotoless" programming as well as the "one entry/one exit" rule. I started out in this field during the spaghetti era (i.e., I am over 50). Dijkstra's work revolutionized how we develop software. – bit-twiddler Mar 17 '11 at 19:31
  • 1
    @David - it's possible to make quite a strong case that Knuth *was*, in some ways, a bad programmer. Your answer is relevant to that - one of Knuths reasons for not wanting an outright ban on `goto` was that some programs couldn't be quite as efficient that way - IIRC he quite literally presented some cycle-counting evidence of exactly that. This is clearly an unhealthy obsession with performance... or at least it would be for most programmers today. Even in the 1960s, I doubt those last few cycles were always worth saving, but there were far more situations where they were. –  Oct 06 '11 at 08:48
  • 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 '16 at 21:23
60

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.

Dima
  • 11,822
  • 3
  • 46
  • 49
  • 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 '11 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". – John R. Strohm Mar 19 '11 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. – kevin cline Oct 06 '11 at 00:42
  • @kevincline as seen with Lua, for instance. – Qix - MONICA WAS MISTREATED Dec 01 '14 at 03:41
  • Old comment, but @Dima, how do you properly manage keeping a class readable that has a large set of public functions that each rely on their own set of wrapped functions? Wouldn't the class be really difficult to read with all of the wrapped functions in the same class file? Would it make sense to group all such wrapped functions into a class of it's own, or simply break up the class into smaller separate classes altogether? – cjsimon Jun 01 '18 at 20:14
  • 1
    @cjsimon you got it. Not only functions should be small. Classes should be small too. – Dima Jun 01 '18 at 20:27
51

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.

Matthew Read
  • 2,001
  • 17
  • 22
  • Yeah, I exaggerated the number of conditions to provide examples of cases to exit. – Mikhail Mar 15 '11 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 05 '15 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. –  Jun 06 '17 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. – Matthew Read Jun 06 '17 at 18:48
  • I'd like to see what the more elegant replacement would be too. I've been programming for a bit now and I'm at a loss. – phorgan1 Jun 16 '20 at 04:53
  • Assigning the conditions to boolean variables with semantic names, and grouping them into helper functions for related checks, would be where I'd start for cleaning up a large amount of such statements. I also like Satanicpuppy's focus on moving it to a proper loop invariant. – Matthew Read Jun 16 '20 at 15:49
  • 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 07 '21 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.

Satanicpuppy
  • 6,210
  • 24
  • 28
  • 2
    +1 very well said, and +1 (if I could do another) for the `while(notDone){ }` approach. – FrustratedWithFormsDesigner Mar 15 '11 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 '11 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. – bit-twiddler Mar 17 '11 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 '11 at 14:57
  • @sjoerd: What it does is tell whoever is reading the code that the break conditions aren't in the loop header. It's not ideal, but it's functionally identical to the original posters code. – Satanicpuppy Mar 17 '11 at 15:07
  • 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. –  Oct 06 '11 at 09:57
  • Easy to change the while loop to for (;;). Seeing that I _know_ there will be some statements that exit the loop, and some other statements that go to the next iteration. – gnasher729 Aug 01 '15 at 12:19
  • I don't assume the loop will run 1000 times. I just assume that when out the `while x < 1000`, I should safely assume `x < 1000` won't hold. IMO, doing otherwise does not help to make the code easier to read/follow. – manu Jul 13 '16 at 22:49
  • @Satanicpuppy Introducing a boolean flag is not the same as using break unless you wrap all your code inside your loop in if statements after each flag change to jump immediatly to the end, if it is set to false, because otherwise your code would execute till the end of the loop block. `Break` statements allow you to do an early exit. Additionally it reduces the number of branches the processor must take to exit a loop.(1 branch vs 2: One to jump to the end and one to exit the loop if the loop condition evaluates to false). – Sebi2020 Feb 05 '21 at 12:52
  • @manu Is that an argument against `break`? With a `break` inside the `while` the guard condition may still hold outside the loop. – Pablo H Dec 07 '21 at 16:24
  • @PabloH The argument is against using `break` in such a way that would make the conditions in the `while` True after the entire block. 99.99% of the time I don't use `break` nor `continue` at all. When I do use `break`, I try it to put as close as possible to the `while` (or other exit conditions) with BIG comments. – manu Dec 10 '21 at 11:13
28

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.

Fizz
  • 588
  • 6
  • 13
  • 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). – DocSalvager Oct 17 '15 at 13:25
  • This is a very detailed and pertinent answer, even after so many years. Thanks for sharing ! – Jordan Breton Sep 04 '22 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.

Bernard
  • 8,859
  • 31
  • 40
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.

Peter Frings
  • 107
  • 2
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.

Joel Etherton
  • 11,674
  • 6
  • 45
  • 55
  • 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 '11 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. – Joel Etherton Mar 15 '11 at 15:17
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.

tamzord
  • 3
  • 2
  • 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. – bit-twiddler Mar 15 '11 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 '11 at 15:48
  • @jsternberg For for the win! :-) – Notinlist Sep 26 '12 at 12:24
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.

Paul Nathan
  • 8,560
  • 1
  • 33
  • 41
  • 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 '11 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 '11 at 18:42
  • 1
    @Mik, maybe "skip this iteration" would be a better description. Yours truly, Dr. I. M. Pedantic – Pete Wilson Mar 15 '11 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. – Paul Nathan Mar 15 '11 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)? – Evan Plaice Mar 19 '11 at 07:34
  • @Evan: math and programming are identical. Look up the denotational/operational semantics. – Paul Nathan Mar 26 '11 at 04:25
  • @Paul Then why don't we use pure math to write software? I'm not saying that they don't accomplish the same goal, I'm saying that programming is more expressive than math when it comes to logical flow. We're capable of expressing more detailed (or complex) logic **because** programming doesn't fall under the same constraints that math does. How do you write a loop in math that breaks execution of the current iteration but resumes at the beginning of the next iteration. It sounds like the person who wrote this answer doesn't fully understand how to use 'continue' statements. – Evan Plaice Mar 26 '11 at 08:43
  • @Evan: I wrote the answer. If you want a discussion of how to describe programmatic semantics, http://www.doc.ic.ac.uk/~svb/AOS/notes.pdf seems to be a relatively concise introduction to the field. Some people do want to move towards pure math: c.f. the Haskell crowd. – Paul Nathan Mar 28 '11 at 04:46
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.

kevin cline
  • 33,608
  • 3
  • 71
  • 142
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.

Deduplicator
  • 8,591
  • 5
  • 31
  • 50
Zeke Hansell
  • 952
  • 6
  • 11
  • 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? – Pete Wilson Mar 15 '11 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 ;-) – Zeke Hansell Mar 15 '11 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! – Zeke Hansell Mar 15 '11 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

Deduplicator
  • 8,591
  • 5
  • 31
  • 50
El Ronnoco
  • 180
  • 4
  • 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? – Evan Plaice Mar 26 '11 at 08: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 '11 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 '11 at 13:10
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.

ACV
  • 173
  • 5
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.

Deduplicator
  • 8,591
  • 5
  • 31
  • 50
sara
  • 2,549
  • 15
  • 23
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.

davidhaskins
  • 2,158
  • 2
  • 18
  • 26
  • 2
    Actually, it's easy to see if you indent properly, have the semantics of those statements internalized and aren't too sleepy. –  Mar 15 '11 at 14:56
  • @delnan - that's a lot of assumptions ;) – davidhaskins Mar 15 '11 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 ;) –  Mar 15 '11 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 '11 at 15:03
  • @Mikhail or even goto... – Gipsy King Mar 15 '11 at 15:37
  • @gipsy-king -- I actually don't like goto, because it doesn't explain if you've exited out of current scope – Mikhail Mar 15 '11 at 18:44
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)

Deduplicator
  • 8,591
  • 5
  • 31
  • 50
FrustratedWithFormsDesigner
  • 46,105
  • 7
  • 126
  • 176
  • 13
    You would really prefer 3 levels of nesting over what I typed above? – Mikhail Mar 15 '11 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. – FrustratedWithFormsDesigner Mar 15 '11 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 '11 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... – FrustratedWithFormsDesigner Mar 15 '11 at 15:27
  • @FrustratedWithFormsDesigner what language is this? is the above pseudo code? are you just writing not and and for clarity of code? – Aditya P Mar 15 '11 at 15:30
  • @AdityaGameProgrammer: It's pseudo-code. – FrustratedWithFormsDesigner Mar 15 '11 at 15:35
  • @FrustratedWithFormsDesigner Ive definitely witnessed varied styles in few short minutes.What coding standards do you follow? – Aditya P Mar 15 '11 at 15:39
  • @AdityaGameProgrammer: I write in this style of pseudo-code because it's how I'm thinking today and I thought the meaning would be pretty clear to all. If it's not, let me know what part of the pseudo-code needs clarification. – FrustratedWithFormsDesigner Mar 15 '11 at 17:19
  • ...would the downvoter at least explain? – FrustratedWithFormsDesigner Mar 15 '11 at 17:46
  • 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' – Zeke Hansell Mar 15 '11 at 18:45
  • @Zeke - his solution is correct, though you may dislike it. Down voting correct solution? – Mikhail Mar 15 '11 at 18:49
  • @Mikail - I'm not down voting anyone. And in this case we aren't talking about a correct solution versus an incorrect solution, we are talking about programming style, which if you have 10 programmers you will have 15 opinions about programming style – Zeke Hansell Mar 15 '11 at 18:56
  • @Zeke Hansell: I don't think the level of nesting here is unreadable. When I do find nesting gets to be a bit too much, that usually when I start looking for ways to start refactoring. As for misinterpretation, I've experienced (both first-hand and from watching others) much more confusion and misinterpretation come up from continue/break code. – FrustratedWithFormsDesigner Mar 15 '11 at 18:56
  • @Frustrated - You've proved my point. This isn't a question of *right* vs *wrong*, it is a question of *style*. Ultimately, each programmer/programming team needs to develop a style that works for them and then be consistent. – Zeke Hansell Mar 15 '11 at 19:46
  • @Zeke and Mikail: Conditional nesting as we know it today was not a common practice when I entered the field. Most of the industrial languages in use at that point did not support the grammatical production. Instead, conditional flow control was handled by an type of grammatical production, which led to spaghetti code. The grammatical production was added because it improved readability and program structure. Indentation was added to further improve readability because it illuminated the sections of code that were conditionally controlled. – bit-twiddler Mar 17 '11 at 13:52
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.

Deduplicator
  • 8,591
  • 5
  • 31
  • 50
umlcat
  • 2,146
  • 11
  • 16
  • 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). – FrustratedWithFormsDesigner Mar 15 '11 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 '11 at 18:41
  • @FrustratedWithFormsDesigner EXACTLY. I put on purpouse to denote why is preferable that method ;-) – umlcat Mar 15 '11 at 23:09
  • however, you have two routines with different semantics; therefore, they are not logically equivalent. – bit-twiddler Mar 17 '11 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. – Evan Plaice Mar 19 '11 at 07:40
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)

Deduplicator
  • 8,591
  • 5
  • 31
  • 50
SuperBloup
  • 101
  • 2
-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.