Evilness of "break" and "continue"


  • Discourse touched me in a no-no place

    @The Flaming Foobar said:

    It's the people who oppose break, continue AND goto who are insane. (And I believe it's largely the same crowd who advocate only one return per function or method, too.)

    While I do agree that for educational purposes, it's good that they are avoided for a good while UNTIL the student thoroughly understands why they needed to avoid them. But as things stand, I do feel that most people take the principle too far, and in fact I believe the need for try-catch(-finally) largely comes from trying to avoid goto at all costs.

    There is no try-catch in C, so we end up seeing a lot of code like this:

    [...]

    And not only do people write functions like that, they'll actually go to great lengths to defend that it is the appropriate way to do it!

    If I were to rewrite the above like this:

    [...]

    A lot of people would protest the "bad practices" I'm using (although it works almost exactly like try-catch). I'd also probably be let known how readability suffers because the code has not been properly indented. 

    You wait until you encounter code where they're using this sort of nastiness (plus loops!) so much that their code indent goes over 80 columns even with a per-level-indent-width of 2. 40 levels of indent and all with complex flag variables used to encode the bits of control structures that didn't go neatly within their scheme.

    When such things are encountered, much refactoring is required. The code needs to become much less deeply indented (and real control structures used for control rather than sharing all that with a smattering of other variables) and the creator of said code needs to be refactored out of any contact with the code too. You know it makes sense. (Hint: encourage them to go and work for your greatest competitor.)



  •  @enfiskutensykkel said:

     Well, I just skimmed through the thread, so somebody else might have pointed it out, but I would prefer

    int a[ ] = {some array of numbers}

    for (i = 0; i < n; ++i) {
    if (a[i] == some element I'm searching for )
    break;
    }

    if (i < n) {
    do_stuff();
    }

    over

    int found = false;
    for (i = 0; !found && i < n; ++i) {
    if (a[i] == some element I'm searching for )
    found = true;
    }

    if (found) {
    do_stuff();
    }

    but that might just be me.

    I would still us an exit condition in a while:

    int a[ ] = {some array of numbers}
    int i = 0;
    while (i < n && a[i] != element we're looking for) {
    i++;
    }
    if (i < n) {
    do_stuff();
    }

    This is a trivial example of course...



  • I do a lot of munging api responses into tables, where part of the response might not be wanted but most is. Continue is an appropriate and readable tool in that case:

    for (var i in json){
      if (json[i].notwanted() ) continue;
      // put dozens of lines of stuff the code actually does when it munges the response here 
    }
    

    Avoids one level of nesting, and keeps it clear what the loop is doing.



  • @swiers said:

    I do a lot of munging api responses into tables, where part of the response might not be wanted but most is. Continue is an appropriate and readable tool in that case:

    for (var i in json){
      if (json[i].notwanted() ) continue;
      // put dozens of lines of stuff the code actually does when it munges the response here 
    }
    

    Avoids one level of nesting, and keeps it clear what the loop is doing.


    What kind of magic json can contain functions?



  • @Ben L. said:

    @swiers said:
    I do a lot of munging api responses into tables, where part of the response might not be wanted but most is. Continue is an appropriate and readable tool in that case:

    for (var i in json){
      if (json[i].notwanted() ) continue;
      // put dozens of lines of stuff the code actually does when it munges the response here 
    }
    

    Avoids one level of nesting, and keeps it clear what the loop is doing.


    What kind of magic json can contain functions?

    The kind where Object.prototype.notwanted = function(){} of course.


  • Considered Harmful

    @Ragnax said:

    @Ben L. said:
    @swiers said:
    I do a lot of munging api responses into tables, where part of the response might not be wanted but most is. Continue is an appropriate and readable tool in that case:

    for (var i in json){
      if (json[i].notwanted() ) continue;
      // put dozens of lines of stuff the code actually does when it munges the response here 
    }
    

    Avoids one level of nesting, and keeps it clear what the loop is doing.


    What kind of magic json can contain functions?

    The kind where Object.prototype.notwanted = function(){} of course.


    Extending Object's prototype? What could go wrong!



  • @ammoQ said:

    @dhromed said:

    Not using break or continue forces another if, another pair of accolades, and another indent level, which I often find a worse deal than two newlines to single out the keyword.

     

    Not really, given the capabilities of todays IDEs and editors. Code folding and stuff.

    But you have to switch code folding on/off, and code cleanness should be independent of the IDE.

    People who dislike continue/break also dislike early returns because they put them in the same bag as multiple returns sprinkled in a method body. Early precondition/eligibility check returns and continues are perfectly fine, I like to call them "guard clauses" and using that term is ime a good starting point to explain why they're a good idea (basically what dhromed said).

    Edit: JDK classes (Collection framework) even use labeled continues (sanitized gotos) in the Sun/Oracle/OpenJdk implementation, for performance reasons in heavily used classes (avoiding a method dispatch if splitting the inner loop). So there is a case even for them, i used them once. Of course measure then optimize, etc..


Log in to reply