The recommended Way to exit a Loop
https://softwareengineering.stackexchange.com/questions/274497
-
07-10-2020 - |
Question
Occasionally - but recurringly - I face the following loop pattern problem:
CodeSnippet1
DO WHILE LoopCondition //LoopCondition depends on some pre-calculation from CodeSnippet1
CodeSnippet2 //CodeSnippet2 relies on LoopConditon=true
CodeSnippet1
LOOP
The problem I see here is the code duplication of CodeSnippet1.
At the first glance, it seems like I should move the condition to the end:
DO
CodeSnippet1
CodeSnippet2
LOOP WHILE LoopCondition
This won't work since CodeSnippet2 assumes LoopCondition=true. The next try would be:
DO
CodeSnippet1
IF LoopCondition THEN CodeSnippet2
LOOP WHILE LoopCondition
Again far from elegant.
In C-like programming languages, one can do the following:
while(complicated-expression-containing-CodeSnippet1-and-LoopCondition) {
CodeSnippet2
}
But
a) this can get difficult to understand and
b) not every programming language can perform arbitrary calculations, especially variable assigments, during evaluation of some loop condition.
Recently, I came up with the following way:
DO //endless loop
CodeSnippet1
IF NOT LoopCondition THEN EXIT LOOP
CodeSnippet2
LOOP
This tends to lead structured programming with loops ad absurdum / reminds me a bit of GoTo programming style.
My Question:
Are there (more or less) objective reasons to prefer one of the mentioned loop programming styles over the others?
EDIT:
I know in many occasions CodeSnippet1
together with LoopCondition
can be encapsulated in a function returning the loop condition, and we're done. I agree with that. But this does not hold in general. Above in b) I tried to hint at "variable assignments". Here in detail:
My favourite minimal but real-world example: Using a BufferedReader
in Java:
line = bufferedReader.readLine();
while(line != null) {
//CodeSnippet2
line = bufferedReader.readLine();
}
vs.
while((line = bufferedReader.readLine()) != null) {
//CodeSnippet2
}
Both variants are not satisfying. Factoring out (line = bufferedReader.readLine()) != null
into a function that returns a boolean has one new problem: How to retrieve line
? Using a global variable / class member just for this purpose?
Solution
Congratulations! You've just reinvented Ada's looping structure. Jean Ichbiah probably reinvented someone else's prior art.
This is de facto possible in a lot of languages, where you can create endless loops with programmed exits. For example, in Python:
while True:
do_stuff()
if not loop_continues:
break
do_more_stuff()
The reason so many languages have a test-at-top loop (while
), a test-at-bottom loop (do until
), and a counting/iterating loop (for
) is that those are the most common patterns, and most likely to be needed. But with modern break
("get me out of this loop!") and continue
("we're ready for the next iteration!") options, there really aren't nearly as many needs for bespoke loop syntax to cover all the options. Python, e.g., does with just for
and while
variants.
The early-exit (break
) and early-continue (continue
) operations are well-structured, with only a few well-designed places they can take you (namely to the bottom/exit of the loop, or to the top of the loop). They are not the "I may jump to pretty much any line!" wildcards of the olden GOTO
days, and so they can get you (and whatever optimizer your compiler toolchain is using) into many fewer sticky situations.
Given that we now have (pretty much irrespective of language used) good structured means to test and manage loop behavior, I'm unclear why anyone would have a strong preference. Test where it makes sense for the algorithm involved: At the top, at the bottom, or some place in between.
OTHER TIPS
Because also of dovals comment:
Wrap codesnippet1 and the loopcondition in a function, because apparently the loopcondition is set by codesnippet1. Which then returns the loopcondition then you get:
DO WHILE CodeSnippet1AndLoopConditionFunction
CodeSnippet2
LOOP
I was told in school that escaping a loop using GOTO or equivalent (such as "break" in C) is a bad style of programming. A school-approved way is to introduce a variable as a switch that once active will cause a loop to exit.
In C, this is a school-approved way to write a loop:
int bool=0;
int count=0;
while (count < 100 && bool==0){
count++;
if (count == 10){
bool=1;
}
}
This is not a school-approved way to write a loop:
int count=0;
while (count < 100){
count++;
if (count == 10){
break;
}
}
However, the non-school approved way uses a few bytes less of stack space (because one less integer is reserved for the program).