2

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?

5
  • 3
    The duplication of CodeSnippet1 is hardly a problem if you shove it into a function.
    – Doval
    Commented Feb 25, 2015 at 23:46
  • @Doval: Thanks. But there can be more difficult occasions, see my edit.
    – fjf2002
    Commented Feb 26, 2015 at 21:30
  • In reaction to your edit: you can still wrap the buffer-reader in a function and provide "line" as an argument to that function. No need for globals : RetunSuccessOnBufferedLineRead(line)
    – Pieter B
    Commented Feb 26, 2015 at 22:17
  • @Pieter B: How would that work? In Java, strings are immutible, thus can't be used as out parameter.
    – fjf2002
    Commented Feb 27, 2015 at 6:23
  • I didn't say anything about merging CodeSnippet1 and the loop condition. But I also don't see why the duplication of a single line is unsatisfying to you.
    – Doval
    Commented Feb 27, 2015 at 15:04

3 Answers 3

12

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.

1
  • Thanks very much for your detailed essay. I can agree with that. --- I never had anything to do with ADA. In fact the exit-in-between-the-loop-idea came stronger to my mind when studying some old PL/I source code.
    – fjf2002
    Commented Feb 26, 2015 at 20:52
0

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
2
  • Thanks. But there can be more difficult occasions, see my edit.
    – fjf2002
    Commented Feb 26, 2015 at 21:31
  • The Single Responsibility Principle would invalidate this solution. In most case I expect "CalculateTrajectoryAndIsLaucnhWindow" would in reality be named "IsLaucnhWindow" and then go on to calculate rocket the launch trajectory - returning a boolean indicating if the rocket is in its launch window.
    – mattnz
    Commented Feb 27, 2015 at 20:07
0

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).

3
  • Thanks for pointing that out. But how does that solve my case, i. e. (A) Prevent having to write at least one of CodeSnippet1 and LoopCondition twice and (B) Prevent using a "complicated C-like condition" that contains both assignment and the LoopCondition?
    – fjf2002
    Commented Feb 27, 2015 at 6:29
  • In my opinion, this is a particularly goofy solution that I've only seen endorsed in academic contexts. The point of avoiding GOTO is to increase the clarity of code, and the opposite is accomplished by adding boolean flag variables to control flow. Commented Feb 27, 2015 at 15:52
  • @fjf2002 I think my 2nd piece of code is your best bet. There is no exact duplication of loop condition and no condition is complicated and no line of code is duplicated. Commented Feb 27, 2015 at 23:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.