SO Vault: Break statements in the real world

0

Full article

StackOverflow sees quite a few threads deleted, usually for good reasons. Among the stinkers, though, lies the occasionally useful or otherwise interesting one, deleted by some pedantic nitpicker - so I resurrect them. 👻

Note: Because these threads are older, info may be outdated and links may be dead. Feel free to contact me, but I may not update them... this is an archive after all.


Break statements In the real world

Question asked by Lodle

Been having a discussion on whirlpool about using break statements in for loops. I have been taught and also read elsewhere that break statements should only be used with switch statements and with while loops on rare occasions.

My understanding is that you should only use for loops when you know the number of times that you want to loop, for example do work on x elements in an array, and while loops should be used every other time. Thus a for loop with a break can be easily refactored into a while loop with a condition.

At my university, you will instantly fail an assignment if you use break anywhere but in a switch statement as it breaks the coding guideline of the university. As I'm still completing my software engineering degree I would like to know from people in the real world.

Comments

it would depend how you use it. In my opinion those who say " never use" are wrong. Even goto statement has its uses. – Anycorn Apr 17 '10 at 3:31

@DR Well not goto. You're kind of crossing the line there. Goto is more like horseradish sauce - hardly at all if any. – bobobobo Jun 19 '10 at 17:24

I find it hard to believe there's a real university which enforces uniform coding standards on all courses. – shoosh Jun 28 '10 at 15:37

Unfortunately, all too often the university isn't anything like the real world. – Loren Pechtel Jul 28 '10 at 4:47

your uni lecturers sound like academic muppets. I recall my uni lecturers. None of them could code for shit. Those who can, do, those who can't - teach! – user206705 Nov 17 '10 at 17:40


Answer by paxdiablo

These generalized rules are rubbish as far as I'm concerned. Use what the language allows in the real world as long as it aids (or doesn't degrade) readability. The guideline against using break is no different to that against using goto. The reason behind people not liking them is because it may lead to spaghetti code, hard to follow.

Note the use of two phrases in that sentence above: The first was "guideline" instead of rule - the only rules are those imposed by the standards. Guidelines are for best practices but you have to understand the reasons behind them, not just follow them blindly.

The second was "may lead to" rather than "does lead to". There are situations where break and its brethren actually lead to more readable code than the alternative (which is often a hugely ugly condition in the looping statement).

For example, they make a lot of sense in finite state machines.

As some have pointed out, break can lead to post-conditions of a loop being variable. By that, I mean that:

for (i = 0; i < 50; i++) {
    if (someCondition) {
        break;
    }
}

can lead to i holding an indeterminate value after the loop.

But you should keep in mind that only matter if you actually care what i is set to after the loop. If the next statement is:

for (i = 0; i < 50; i++) { ... }

then it doesn't matter at all.

A piece of code like:

while (x != 0) {
    y = doSomethingWith (x);
    if (y == 0) break;
    process (y);

    z = doSomethingElseWith (x);
    if (z == 0) break;
    process (z);

    x--;
}

violates this guideline and can be refactored into something that doesn't but there is nothing unreadable about this piece of code. You can clearly see all flows of control at a single glance.

You should use the language features that make sense to your situation. Where guidelines should be enforced and where they should be ignored comes with experience.


Answer by Norman Ramsey (Apr 17, 2010)

I've been told by professors and peers at my university that using the break statement is bad practice

Come visit Tufts and our professors will tell you otherwise.

The arguments against break boil down to one principle: break requires non-local reasoning, and a language with break requires a much more complicated semantic framework than a language without break. (For the experts in the room, instead of using simple tools like predicate transformers or Hoare logic, you have to reach for something like continuations, or at the very least, a context semantics.)

The problem with this argument is that it puts simplicity of semantics ahead of programmers' real needs. There are lots of programs with natural loops that have more than one exit. Programming languages need to support these loops in a way that is more effective than introducing extra Boolean variables to govern the control flow.

For some expert testimony on the value of multiple exits from control-flow constructs, I recommend two papers:

  • Structured Programming With goto Statements by Donald E. Knuth. Don goes to great length to explain why certain kinds of gotos should be allowed in Pascal. Most of these gotos are equivalent to some form of break, which hadn't quite been invented yet when Don wrote the paper.

  • Exceptional Syntax by Nick Benton and Andrew Kennedy. The topic may seem unrelated, but throwing an exception is a nonlocal exit, just like break. (In Modula-3, break was defined to be an exception.) It's a great paper showing how language designers need to be more imaginative in designing syntax to support multiple exits.

If you really want to annoy your professors, ask them if the return statement is bad practice. If they say "no", you've got them: "But isn't return a control operator, just like break? And isn't it the case that introducing return intro a structured program creates all the same semantic difficulties that introducing break does?" Watch them squirm.

Is using the break statement bad practice?

No. The break statement is a valuable tool in your toolbox, just like return or exceptions. Like other tools, it can be misused, but there is nothing inherently bad about it, and in fact the break statement is pretty easy to use in sane and sensible ways.

Your professors should learn some more powerful semantic methods that can tame the break statement.


Answer by Joel (Apr 17, 2010)

This comes from the idea that there should be one way IN a method and one way OUT. Same with loops. I've had some instructors tell me that I shouldn't use more than one return or any break/continue because it creates "spaggetti code" and it's hard to follow the path. Instead, they say to set a flag and use an if statement rather than just break out. I completely disagree with this idea. I think in a lot of cases having more than one return or a break/continue statement is much more readable and easier to follow.


Answer by Stephen C

I've been told by professors and peers at my university that using the break statement is bad practice

The first thing to realize is that many of those people have never actually been professional software engineers, and never had to work on a large code base written by many developers over many years. If you do this, you learn that simplicity, clarity, consistency and use of accepted idioms are more important in making code maintainable than dogma like avoiding break/continue/multiple return.

I personally have no problems reading and understanding code that uses break to get out of loops. The cases where I find a break unclear tend to be cases where the code needs to be refactored; e.g. methods with high cyclomatic complexity scores.

Having said that, your professors have the right motivation. That is, they are trying to instill in you the importance of writing clear code. I hope they are also teaching you about the importance of consistent indentation, consistent line breaking, consistent white space around operators, identifier case rules, meaningful identifiers, comments and so on ... all of which are important to making your code maintainable.


Answer by Greg (Oct 19, 2008)

I don't see any harm in using break - it's useful and simple. The exception is when you have a lot of messy code inside your loop, it can be easy to miss a break tucked away in 4 levels of ifs, but in this case you should probably be thinking about refactoring anyway.

Edit: IMHO it's much more common to see break in a while than a for (although seeing continue in a for is pretty common) but that doesn't mean it's bad to have one in a for.


Answer by Greg B

I think it's a completely pompous and ridiculous rule to enforce.

I often use break within a for loop. If i'm searching for something in an array and don't need to keep searching once I find it, I will break out of that loop.

I agree with @Konrad Rudolph above, that any and all features should be used as and when the developer sees fit.

In my eye, a for loop is more obvious at a glance than a while. I will use a for over a while any day unless a while is specifically needed. And I will break from that for if logic requires it.


Answer by Richard Harrison (Oct 19, 2008)

My rule is to use any and all features of the language where it doesn't produce obscure or unreadable code.

So yes, I do on occasion use break, goto, continue


Answer by Rob Walker (Oct 19, 2008)

I often use break inside a for loop.

The advantage of a for loop is that the iterator variable is scoped within the expression. If a language feature results in less lines of code, or even less indented code then IMHO it is generally a good thing and should be used to improve readability.

e.g.

for (ListIt it = ...; it.Valid(); it++)
{
  if (it.Curr() == ...)
  {
     .. process ...
     break;
   }
}

Rewriting this using a for loop would require several more lines, and leak the iterator out of the scope of the loop.

(Pedantic points: I only want to act on the first match, and the condition being evaluated isn't suitable for any Find(...) method the list has).


Answer by Cervo (Oct 19, 2008)

Break is useful for avoiding nesting. Also there are many times that it is useful to prematurely exit a loop. It also depends on the languages. In languages like C and Java a for loop basically is a while loop with an initialization and increment expression.

is it better to do the following (assume no short circuit evaluation)

list = iterator on something
while list.hasItem()
  item = list.next()
  if item passes check
      if item passes other check
            do some stuff
            if item passes other check
                  do some more stuff
                  if item is not item indicating end of list
                        do some more stuff
                  end if
            end if
       end if
   end if
end while

or is it better just to say

while list.hasItem()
     item = list.next()
     if check fails continue
       .....
     if checkn fails continue
     do some stuff
     if end of list item checks break
end while

For me it is better to keep the nesting down and break/continue offer good ways to do that. This is just like a function that returns multiple times. You didn't mention anything about continue, but in my opinion break and continue are of the same family. They help you to manually change loop control and are great at helping to save nesting.

Another common pattern (I actually see this in university classes all the time for reading files and breaking apart strings) is

currentValue = some function with arguments to get value
while (currentValue != badValue) {
    do something with currentValue
    currentValue = some function with arguments to get value
}

is not as good as
while (1) {
    currentValue = some function with arguments to get value
    if (currentValue == badValue)
       break
    do something with currentValue
}

The problem is that you are calling the function with arguments to create currentValue twice. You have to remember to keep both calls in sync. If you change the arguments for one but not the other you introduce a bug. You mention you are getting a degree in software engineering, so I would think there would be emphasis on not repeating yourself and creating easier to maintain code.

Basically anyone who says any control structure is bad and completely bans it is being closed minded. Most structures have a use. The biggest example is GOTO. A lot of people abused it and jumped in the middle of other sub procedures, and basically jumped forwards/backwards all over the code and gave it a bad name. But GOTO has its uses. Using GOTO to exit a loop early was a good use, now you have break. Using GOTO to centralize exception handling was another good use. Now you have try/catch exception handling in many languages. In assembly there is only GOTO for the most part. And using that you can create a disaster. Or you can create our "structured" programming structures. In truth I generally don't use GOTO except in excel VBA because there is no equivalent to continue (that I know of) and error handling code in VB 6 utilizes goto. But I still would not absolutely dismiss the control structure and say never...

Unfortunately the reality is that if you don't want to fail, you will have to avoid using break. It is unfortunate that university doesn't have more open minded people in it. To keep the level of nesting down you can use a status variable.

status variable = true
while condition and status variable = true
  do stuff
  if some test fails
    status variable = false
  if status variable = true
     do stuff
  if some test fails
     status variable = false
  ....
end while

That way you don't end up with huge nesting.


Answer by Duck (Apr 17, 2010)

Makes switch statements a whole lot easier.


Answer by Sol (Oct 19, 2008)

I would argue your teachers' prohibition is just plain poor style. They are arguing that iterating through a structure is a fundamentally different operation than iterating through the same structure but maybe stopping early, and thus should be coded in a completely different way. That's nuts; all it's going to do is make your program harder to understand by using two different control structures to do essentially the same thing.

Furthermore, in general avoiding breaks will make your program more complicated and/or redundant. Consider code like this:

for (int i = 0; i < 10; i++)
{
   // do something
   if (check on i) 
        break;
   // maybe do something else
}

To eliminate the break, you either need to add an additional control boolean to signal it is time to finish the loop, or redundantly check the break condition twice, once in the body of the loop and once in the loop's control statement. Both make the loop harder to understand and introduce more opportunities for bugs without buying you any additional functionality or expressiveness. (You also need to hoist the declaration of i out of the loop's control structure, adding another scope around the entire mess.)

If the loop is so big you cannot easily follow the action of the break statement, then you'd be better off refactoring the loop than adding to its complexity by removing the break statement.


Answer by stakx

Edit: First of all, sorry if this answer seems somewhat long-winded. However, I'd like to demonstrate where my expressed opinion about the break statement (bold text at the end of my answer) comes from.


One very good use case for the break statement is the following. In loops, you can usually check a break condition in either of two places: Either at the loop's beginning, or at the loop's end:

while (!someBreakCondition)
{
    ...
}

do
{
    ...
} while (!someBreakCondition)

Now, what do you do when, for some reason, you cannot put your break condition in either of these places, because e.g. you first need to retrieve a value from somewhere before you can compare it to some criterion?

// assume the following to be e.g. some API function that you cannot change:
void getSomeValues(int& valueA, int& valueB, int& valueC)
//                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//                           out parameters
{
    ...
}

while (true)
{
    int a, b, c;
    getSomeValues(a, b, c);
    bool someBreakCondition = (b = ...);

    ...   // <-- we do some stuff here
}

In the above example, you could not check for b directly inside the while header, because it must first be retrieved from somewhere, and the way to do that is via a void function. No way to put that into the while break condition.

But it may also be too late to wait until the end of the loop for checking the condition, because you might not want to execute all the code in the loop body:

do
{
    int a, b, c;
    getSomeValues(a, b, c);
    bool someBreakCondition = (b = ...);

    ...   // <-- we want to do some stuff here, but only if !breakCondition
} while (!someBreakCondition);

In this situation, there's two approaches how to avoid executing the ... when someBreakCondition is true:

1) without using break

    ...  // as above

    if (!someBreakCondition)
    {
        ...  // <-- do stuff here
    }
} while (!someBreakCondition);

2) with break

    ...  // as above
    if (someBreakCondition) break;

    ...  // <-- do stuff here
} while (true);

Your professor would obviously favour option 1) (no break). I personally think that's not a nice option, because you have to check the break condition in two places. Option 2) (use break) resolves that problem. Admittedly though, option 1) has the advantage that it becomes more easily recognisable through code indentation under what condition the ... code will execute; with option 2), you have to go up in your source code to find out that program execution might never actually get to some place further down.

In conclusion, I think using or not using break in this (quite frequent) scenario it really comes down to personal preference about code legibility.


Answer by Jon Ericson (Oct 21, 2008)

break is an extremely valuable optimization tool and is especially useful in a for loop. For instance:

-- Lua code for finding prime numbers
function check_prime (x)
   local max = x^0.5;

   for v in pairs(p) do
      if v > max then break end;

      if x%v==0 then 
         return false
      end 
   end
   p[x] = true;
   return x 
end

In this case, it isn't practical to set up the for loop to terminate at the right moment. It is possible to re-write it as a while loop, but that would be awkward and doesn't really buy us anything in terms of speed or clarity. Note that the function would work perfectly well with out the break, but it would also be much less efficient.

The huge advantage of using break rather than refactoring into a while loop is that the edge cases are moved to a less important location in the code. In other words, the main condition for breaking out of a loop should be the only condition to avoid confusion. Multiple conditions are hard for a human to parse. Even in a while loop, I'd consider using break in order to reduce the number of break conditions to just one.


I'm aware that this is not the most efficient prime checker, but it illustrates a case where break really helps both performance and readability. I have non-toy code that would illustrate it, but require more background information to set it up.


Answer by Konrad Rudolph (Oct 19, 2008)

If it's a guideline that's enforced by the corrector, you don't really have the choice.

But as guidelines go, this one seems to be excessive. I understand the rationale behind it. Other people argue (in the same vein) that functions must only have one single exit point. This may be helpful because it can reduce control flow complexity. However, it can also greatly increase it.

The same is true for break in for loops. Since all loop statements are basically idempotent, one kind can always be substituted for any other. But just because you can doesn't mean that this is good. The most important coding guideline should always be “use your brain!”


Answer by Stefan Rådström (Oct 19, 2008)

In a way I can understand the professor's point of view in this matter, but only as a way to teach the students how to solve problems in a (some kind of) standard fashion. Learn to master these rules, then you are free to break against them as you wish, if that will make the code easier to understand, more effective, or whatever.


Answer by Ken Paul (Oct 21, 2008)

  1. While in school, follow the defined guidelines. Some guidelines are arbitrary, and exist primarily for consistency, ease of grading, or to keep within the teacher's limited understanding. The best balance between maximizing learning and maximizing grades is to follow the guidelines.
  2. In the real world, the balance shifts to maximizing benefit for your employer. This usually requires a focus on readability, maintainability and performance. Since programmers rarely agree on what maximizes these qualities, employers typically attempt to enforce even more arbitrary guidelines. Here the stakes are keeping your job and possibly climbing to a leadership position where you can actually influence the standards.

Answer by Vivin Paliath (Apr 17, 2010)

I tend to shy away from breaks. Most of the time, I've found that a flag is sufficient. Of course, this doesn't mean that breaks are always bad. They do have their uses. Your teachers and peers are right about it being a "get out of jail free" card. This is because breaks, like gotos, have a very high potential for abuse. It's often easier to break out of a loop than to figure out how to structure the loop correctly. In most cases, if you think about your algorithm and logic, you will find that you do not need a break.

Of course, if your loop ends up having a whole bunch of exit conditions, then you need to either rethink your algorithm or use breaks. I tend to really sit and think about my algorithms before deciding to use a break. When you write code and you get that voice in your head that says There has to be a better way than this!, you know it's time to rewrite your algorithm.

As far as loops are concerned, I use for loops when want to iterate over a collection of items with a known bound and I know that there are no other exit conditions. I use a while loop when I want to run a series of statements over and over again until something happens. I usually use while loops if I am searching for something. In this case, I don't break out of the while. Instead, I use a flag because I think the while loop in its entirety reads more like English and I can tell what it's doing. For example:

int i = 0;
while(i < size && !found) {
   found = (value == items[i]);
   i++;
}

The way I read that in English in my head is While i is lesser than the total count of items and nothing is found. That, versus:

int i = 0;
for(int i = 0; i < count; i++) {
   if(value == items[i]) {
      break;
   }
}

I actually find that a bit harder to read because I can't tell immediately from the first line what the loop is actually doing. When I see a for loop, I think Ok, I'm running over a known list of items no matter what. But then I see an if in that loop and then a break inside the if block. What this means is that your loop has two exit conditions, and a while would be a better choice. That being said, don't do this either:

int i = 0;
while(i < count) {
   if(value == items[i]) {
      break;
   }
   i++;
}

That's not much better than the for with the break. To sum it all up, I'd say use break as a last resort, and only if you are sure that it actually will make your code easier to read.


Answer by Steve Jessop (Apr 17, 2010)

Those who claim that it is bad say that it's a "get out of jail free card" and that you can always avoid using it.

They may claim that, but if that's their actual argument then it's nonsense. I'm not in jail, and as a programmer I'm not in the business of avoiding things just because they can be avoided. I avoid things if they're harmful to some desired property of my program.

There's a lot of good discussion here, but I suggest that your professors are not idiots (even if they're wrong), and they probably have some reason in mind when they say not to use break. It's probably better to ask them what this is, and pay attention to the answer. You've given your "guess", but I propose to you that they would state their case better than you state it. If you want to learn from them, ask them to explain the exact details, purpose, and benefits of their coding guideline. If you don't want to learn from them, quit school and get a job ;-)

Admittedly, I don't agree with their case as you've stated it, and neither do many others here. But there's no great challenge in knocking down your straw-man version of their argument.


Answer by Jonah (Jun 26, 2010)

Here is a good use-case in PHP:

foreach($beers as $beer) {
    $me->drink($beer);

    if ($me->passedOut) {
        break; //stop drinking beers
    }
}

Answer by OregonGhost (Oct 19, 2008)

I also learned at uni that any functions should have only a single point of exit, and the same of course for any loops. This is called structured programming, and I was taught that a program must be writable as a structogram because then it's a good design.

But every single program (and every single structogram) I saw in that time during lectures was ugly, hardly readable, complex and error-prone. The same applies to most loops I saw in those programs. Use it if your coding guidelines require it, but in the real world, it's not really bad style to use a break, multiple returns or even continue. Goto has seen much more religious wars than break.


Answer by Jay Bazuzi (Oct 19, 2008)

Most of the uses of break are about stopping when you've find an item that matches a criteria. If you're using C#, you can step back and write your code with a little more intent and a little less mechanism.

When loops like this:

foreach (var x in MySequence)
{
    if (SomeCritera(x))
    {
        break;
    }
}

start to look like:

from x in mySequence
where x => SomeCriteria(x)
select x

If you are iterating with while because the thing you're working on isn't an IEnumerable<T>, you can always make it one:

    public static IEnumerable<T> EnumerateList<T>(this T t, Func<T, T> next)
    {
        while (t != null)
        {
            yield return t;
            t = next(t);
        }
    }

Answer by DJClayworth (Oct 21, 2008)

The rule makes sense only in theory. In theory for loops are for when you know how many iterations there are, and while loops are for everything else. But in practice when you are accessing something for which sequentil integers are the natural key, a for loop is more useful. Then if you want to terminate the loop before the final iteration (because you've found what you are looking for) then a break is needed.

Obey your teacher's restriction while you are writing assignments for him. Then don't worry about it.


Answer by tvanfosson (Oct 19, 2008)

I understand the issue. In general you want to have the loop condition define the exit conditions and have loops only have a single exit point. If you need proof of correctness for your code these are invaluable. In general, you really should try to find a way to keep to these rules. If you can do it in an elegant way, then your code is probably better off. However, when your code starts to look like spaghetti and all the gymnastics of trying to maintain a single exit point get in the way of readability, then opt for the "wrong" way of doing it.

I have some sympathy for your instructor. Most likely he just wants to teach you good practices without confusing the issue with the conditions under which those practices can be safely ignored. I hope that the sorts of problems he's giving you easily fit into the paradigm he wants you to use and thus failing you for not using them makes sense. If not, then you get some experience dealing with jerks and that, too, is a valuable thing to learn.


Answer by Thomas Padron-McCarthy (Mar 17, 2009)

Another view: I've been teaching programming since 1986, when I was teaching assistant for the first time in a Pascal course, and I've taught C and C-like languages since, I think, 1991. And you would probably not believe some of the abuses of break that I have seen. So I perfectly understand why the original poster's university outlaws it. It is also a good thing to teach students that just because you can do something in a language, that doesn't mean that you should. This comes as a surprise to many students. Also, that there is such a thing as coding standards, and that they may be helpful -- or not.

That aside, I agree with many other posters that even if break can make code worse, it can also make it better, and, like any other rule, the no-breaks rule can and (sometimes) should be broken, but only if you know what you're doing.


Answer by Pulsehead

You are still in school. Time to learn the most important mantra that colleges require of you:
Cooperate and Graduate.

It's good that your school has a guideline, as any company you work for (worth a plugged nickel) will also have a coding guideline for whatever language you will be coding in. Follow your guideline.


Answer by Samuel (Apr 17, 2010)

I don't think there is anything wrong with using breaks. I could see how using a break can be seen as skipping over code but it's not like a goto statement where you could end up anywhere. break has better logic, "just skip to the end of the current block".

slightly off topic...(couldn't resist)
http://xkcd.com/292/


Answer by Cervo

@lodle.myopenid.com

In your answer the examples do not match. Your logic is as follows in the example in the equation and example A in your answer:

while X != 0 loop
   set y
   if y == 0 exit loop
   set z
   if z == 0 exit loop
   do a large amount of work
   if some_other_condition exit loop
   do even more work
   x = x -1

example b:
while X != 0 loop
  set y
  if y == 0
    set z
  elseif z == 0
    do a large amount of work
  elseif (some_other_condition)
    do even more work
  x--

This is absolutely not the same. And this is exactly why you need to think about using break.

First of all in your second example you probably meant for the if var == 0 to be if var != 0, that is probably a typo.

  1. In the first example if y or z is 0 or the other condition is met you will exit the loop. In the second example you will continue the loop and decrement x = x - 1. This is different.
  2. You used if and else if. In the first example you set y, then check y, then set z then check z, then you check the other condition. In the second example you set y and then check y. Assuming you changed the check to y != 0 then if y is not 0 you will set z. However you use else if. You will only check Z != 0 (assuming you changed it) if y == 0. This is not the same. The same argument holds to other stuff.

So basically given your two examples the important thing to realize is that Example A is completely different from Example B. In trying to eliminate the break you completely botched up the code. I'm not trying to insult you or say you are stupid. I'm trying to overemphasize that the two examples don't match and the code is wrong. And below I give you the example of the equivalent code. To me the breaks are much easier to understand.

The equivalent of example A is the following

  done = 0;
  while X != 0 && !done {
    set y
    if y != 0 {
      set z
      if z != 0 {
        do large amount of work
        if NOT (some_other_condition {
          do even more work
          x = x - 1
        } else
          done = 1;
      } else
        done = 1;
    } else
      done = 1;
  }

As you can see what I wrote is completely different from what you wrote. I'm pretty sure mine is right but there may be a typo. This is the problem with eliminating breaks. A lot of people will do it quickly like you did and generate your "equivalent code" which is completely different. That's why frankly I'm surprised a software engineering class taught that. I would recommend that both you and your professor read "Code Complete" by Steve McConnell. See http://cc2e.com/ for various links. It's a tough read because it is so long. And even after reading it twice I still don't know everything in it. But it helps you to appreciate many software implementation issues.


Answer by Dustin Getz (Oct 21, 2008)

break typically does make loops less readable. once you introduce breaks, you can no longer treat the loop as a black box.

while (condition)
{
   asdf
   if (something) break;
   adsf
}

cannot be factored to:

while (condition) DoSomething();

From Code Complete:

A loop with many breaks may indicate unclear thinking about the structure of the loop or its role in the surrounding code. Excessive breaks raises often indicates that the loop could be more clearly expressed as a series of loops. [1]

Use of break eliminates the possibility of treating a loop as a black box1. Control a loop's exit condition with one statement to simplify your loops. 'break' forces the person reading your code to look inside to understand the loop's control, making the loop more difficult to understand. [1]

  1. McConnell, Steve. Code Complete, Second Edition. Microsoft Press © 2004. Chapter 16.2: Controlling the Loop.

Answer by Robert Rossney (Oct 21, 2008)

Out of curiosity, I took a little tour of the codebase I'm working on - about 100,000 lines of code - to see how I'm actually using this idiom.

To my surprise, every single usage was some version of this:

foreach (SomeClass x in someList)
{
   if (SomeTest(x))
   {
      found = x;
      break;
   }
}

Today, I'd write that:

SomeClass found = someList.Where(x => SomeText(x)).FirstOrDefault();

which, through the miracle of LINQ deferred execution, is the same thing.

In Python, it would be:

try:
   found = (x for x in someList if SomeTest(x)).next()
except StopIteration:
   found = None

(It seems like there should be a way to do that without catching an exception, but I can't find a Python equivalent of FirstOrDefault.)

But if you're not using a language that supports this kind of mechanism, then of course it's OK to use the break statement. How else are you going to find the first item in a collection that passes a test? Like this?

SomeClass x = null;
for (i = 0; i < SomeList.Length && x == null; i++)
{
   if (SomeTest(SomeList[i]))
   {
      x = SomeList[i];
   }
}

I think break is just a wee bit less crazy.


Answer by Personman

In general, anything that makes execution jump around and isn't a function call has the potential to make your code more confusing and harder to maintain. This principle first gained widespread acceptance with the publication of Dijkstra's Go To Statement Considered Harmful article in 1968.

break is a more controversial case, since there are many common use cases and is often pretty clear what it does. However, if you're reading through a three- or four-deep nested loop and you stumble upon a break (or a continue), it can be almost as bad. Still, I use it sometimes, as do many others, and it's a bit of a personal issue. See also this previous StackOverflow question: Continue Considered Harmful?


Answer by Brian Gianforcaro (Apr 17, 2010)

I believe your professor's are just trying (wisely) to instil go coding practices in you. Break's, goto's, exit(), etc can often be the cause behind extraneous bugs throughout code from people new to programming who don't really have a true understanding of what's going on.

It's good practice just for readability to avoid intruding possible extra entrances and exit's in a loop/code path. So the person who reads your code won't be surprised when they didn't see the break statement and the code doesn't take the path they thought it would.


Answer by Pavel Radzivilovsky

In the real world, few people care about style. However, break from loop is an okay thing by strictest coding guidelines, such as that of Google, Linux kernel and CppCMS.

The idea of discouraging break comes from a famous book, Structured Programming by Dijkstra http://en.wikipedia.org/wiki/Structured_programming that was the first one to discourage goto. It suggested an alternative to goto, and suggested principles which might have misled your professors.

Since then, a lot changed. Nobody seriously believes in one point of return, but, the goto - a popular tool at the time of the book - was defeated.


Answer by S.Lott

In the real-world, I look at every break statement critically as a potential bug. Not an actual bug, but a potential bug. I challenge the programmers I work with on every break statement to justify its use. Is it more clear? Does it have the expected results?

Every statement (especially every composite statement) has a post-condition. If you can't articulate this post-condition, you can't really say much about the program.

Example 1 -- easy to articulate.

while not X:
   blah blah blah
assert X

Pretty easy to check that this loop does that you expected.

Example 2 -- harder to articulate.

while not X:
   blah
   if something I forgot: 
      break
   blah blah
   if something else that depends on the previous things:
      break
   blah
assert -- what --?
# What's true at this point?  X?  Something?  Something else?
# What was done?  blah?  blahblah?

Not so easy to say what the post-condition is at the end of that loop. Hard to know if the next statements will do anything useful.

Sometimes (not always, just sometimes) break can be bad. Other times, you can make the case that you have loop which is simpler with a break. If so, I challenge programmers to provide a simple, two-part proof: (1) show the alternative and (2) provide some bit of reasoning that shows the post-conditions are precisely the same under all circumstances.

Some languages have features that are ill-advised. It's a long-standing issue with language design. C, for example, has a bunch of constructs that are syntactically correct, but meaningless. These are things that basically can't be used, even though they're legal.

break is on the hairy edge. Maybe good sometimes. Maybe a mistake other times. For educational purposes—it makes sense to forbid it. In the real world, I challenge it as a potential quality issue.


Shared with attribution, where reasonably possible, per the SO attribution policy and cc-by-something. If you were the author of something I posted here, and want that portion removed, just let me know.

Author

Grant Winney

Is there anything more satisfying than sharing knowledge? Of teaching someone and witnessing their "ah ha" moment? I hope you found something here today that led to your very own "ah ha" moment! 💡


Comments