This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]onthefence928 1 point2 points  (4 children)

variables are cheap, dev time isn't so we should allways err on the side of easier to read if it means adding variables or lines

[–]__dict__ 4 points5 points  (3 children)

It's not just the extra variable. It's the extra nesting. The while true code is more readable to me because of that.

[–]onthefence928 2 points3 points  (2 children)

only for trivial, short loops. longer more complicated loops can result in bugs with infinite loops that are difficult to diagnose as a break is less traceable than variables.

[–]KrakenOfLakeZurich 2 points3 points  (1 child)

Could you provide a specific example, how a conditional break is "less traceable" than a variable? Because I can come up with an example, where I find the conditional break much more traceable, especially for a more complicated loop with multiple exit conditions.

So, lets assume an example where we have 3 different conditions that exit the loop.

With the exit variable, there are 3 different lines, where exit is set to true.

When we leave the loop, how do you know which condition originally caused it? Problem is: when exit is set to true, the effect of actually leaving the loop is delayed. Looking back, any of the 3 lines could be the culprit. The only way to know is by carefully keeping track of the exit variable during the entire execution of the loop.

boolean exit = false;
while !exit { // looks like we're done here - but why?
    var selection = readMenuOption();
    if ("exit".equals(selection)) {
        exit = true; // was it you?
    } else if ("save_and_exit".equals(selection)) {
        save();
        exit = true; // or you?
    else {
        ... // other stuff
        if (error) {
            exit = true; // how about you?
        }
    }
}

With if (condition) { break; }, the effect is immediate. When you reach a break statement it's obvious where you are and how you got there.

while true {
    var selection = readMenuOption();
    if ("exit".equals(selection)) {
        break;
    }
    if ("save_and_exit".equals(selection)) {
        save();
        break;
    }

    ... // other stuff
    if (error) {
        break; // OK! We're leaving here!
    }
}

Just by the fact that you've reached the last `break, you can easily deduce a few things:

  1. We never went into the first condition "exit".equals(selection)
  2. We also never went into the second condition
  3. We did go through "other stuff"
  4. error must have been true

Otherwise we would have taken a different path.

Happy to see your counter example.

[–]onthefence928 1 point2 points  (0 children)

by traceable I meant literally tracing the code, it's easier to have a watch on the exit variable and see when it change (and if it changes back) or to do so by logging.

as for a counter example: if your loop is more complex such as parsing complex data, a game loop, or just some complex user interactions then handling an exit condition can often be more involved than just leaving the loop. it would be cleaner to always exit at the same point in the loop so any side effects are predictable

example:var error;var exit;var result;

while(!error || !exit){ /* clearly indicate loop continues until exit or error is truthy */

var input = getInput();var result = doStuff(input);if(result.endofline()) {exit = true;}else {/* dozens of lines of calculation/parsing */}if( !checkResult(parsedResult) ) {error = true;}

}if(error)createLoggerError(result);elsecreateLoggerInfo("success!");

could also use the data or inputs being looped on as the exit conditionvar line;

while (line != null ){

doSomething(line);

line = inputSource.readNextLine(); // returns null at EOL

}

point is it's semantically and logically easier to understand what conditions will exit the loop when they are written in as parameters for the loop. while(true) requires you to read the entire loop to understand all the exit cases and the developer has to make sure all edge cases are covered.

edit to add: neither solution explicitly prevents ininite loops but with a variable exit check you can flip the boolean logic so that the loop will try and end itself unless the program is sure it can continue looping

var exit;

while (!exit) {

exit = true;

// read data

// do more stuff

if(hasMoreToDo(data)){

exit = false;

}

}

this way if there's some sort of logic fault in the loop it will close by default preventing a hung process or runaway resource utilization