23. While Loops

In these notes you will learn:

  • How to create an infinite loop using a while-loop.
  • How to write and trace while-loops that perform simple tasks, such as incrementing variables.

23.1. Introduction

Suppose you want to print the numbers from 1 to 1000 on the screen. We could simply write the statements necessary to do it, something like:

println(1);
println(2);
println(3);

// ...

println(1000);

But that’s a painfully tedious solution that takes up a lot of space (we’d need a thousand lines!). Further, ArrayLists and the for-each loop won’t help here because we still need to insert 1000 elements into the ArrayList before we can use a for-each block to print out all of the elements.

Luckily, Processing provides a much better of repeating tasks called a while-loop, which is a way to repeat a block of code zero or more times.

23.2. While Loops as If-statements with Bells

We’ve seen already the general structure of an if-statement:

if (some-condition) {
    // do some exciting stuff.
}

This statement will execute exactly once if some-condition evaluates to true.

A while-loop follows a similar approach, repeatedly. That is a while-loop that looks like this:

while (some-condition) {
    // do some exciting stuff!
}

Will execute the code inside its curly braces for as long as some-condition is true. More precisely, the first time Processing reaches a line containing the keyword while, some-condition will be evaluated. If it evaluates to true the code inside the while-loop is executed. Processing will then evaluate some-condition again. If some-condition evaluates to false, the code inside inside the loop is not executed again. Otherwise, the code in the loop will execute again, and Processing will check some-condition again, etc.

This leads to interesting situation, which we will see in our first while-loop example.

23.3. Infinite Loops

The simplest kind of loop is a loop that never stops. i.e. an infinite loop. We can use a while-loop to create an infinite loop like this:

while(true) {
    print("Hello");
}

The code above will print “Hello” forever.

Note

In practice, infinite loops are often a sign of a bug in your program, and fixing an infinite loop usually involves making the condition in parentheses one that eventually stops.

Warning

Be wary of infinite loops inside of Processing’s setup() function. Try it and see what happens.

23.4. Loops that Stop

Now suppose we want to print the numbers 1 to 10 on the screen using a while loop. Somehow we need the loop to stop after it has called println 10 times. The standard technique for doing this is to use a variable, say i, to keep track of how many times the block of code in the while-loop has been executed. For example:

int i = 1;
while (true) {
    println(i);
    ++i; // adds 1 to i (same as i += 1)
}

println("done");

This loop prints this:

1
2
3
4
.
.
.

Again, this is an infinite loop. But it illustrates the important idea of incrementing a variable inside a loop.

How do we get a while-loop to stop? We have to make the condition inside the parenthesis false. We can write any boolean expression as the condition of a while-loop. As long as we make sure that this condition is eventually false, we are guaranteed that the while loop will terminate. For example:

int i = 1;
while(i <= 10) {
    println(i);
    ++i;
}

println("done");

Now the while-loop condition is i <= 10, which means that the block of code inside the loop will only be executed when i <= 10 is true, or put another way, for these values of i: 1, 2, 3, 4, 5, 6, 7, ,8, 9, 10. After 10 iterations the i will get the value 11, so the condition i <= 10 will evaluate to false, and the loop will stop. The next line to be executed is the line that prints “done” to the screen.

In English, what this while-loop is saying is “As long as i is at most 10, print i to the screen and increment the value of i”

And that’s really all there is to while-loops: the condition at the top can be anything, and it decides whether or not the code inside the braces is executed. When the condition is false the loop is over, i.e. it is terminated.

23.5. Tracing through a While-Loop

Look again at this loop:

int i = 0;
while(i <= 0) {
    println(i);
    ++i;
}

println("done");

What does it print? The best way to understand loops is to “play computer” and trace the code by hand, keeping track of the balue of i as you go. Tracing it by hand, you would do something like this:

  • i is initially set to 1.
  • The first time the loop condition is checked, i is is 1, and so i <= 10 evaluates to true. Therefore println(i) is executed, causing 1 to be printed to the screen. Then the value of i is incremented, making it equal to 2.
  • After the code block is executed, the loop condition is checked again. Since i is 2, i <= 10 is still true, and so 2 is printed and i is incremented to 3.
  • After the code block is executed, the loop condition is checked again. Since i is 3, i <= 10 is still true and so 3 is printed to the screen and i is incremented to 4.

You can see how the pattern continues. Eventually, i gets the value 10. The loop condition i <= 10 is true, so 10 is printed and i is incremented to 11.

But now when the loop condition is checked, i <= 10 evaluates to false, because i is 11. A false loop condition causes the program to skip over the block of code directly underneath it and instead execute whatever statements follow the loop. The overall effect is:

1
2
3
4
5
6
7
8
9
10
done

Tracing loops is a valuable skill that you should practice. Loops in real programs can get tricky and tracing a loop by hand is often the best way to understand what it does.

23.6. Example: Adding Objects to an ArrayList

In previous notes we saw code like this for adding a lot of bouncing ball objects to an ArrayList:

// Ball class here

ArrayList<Ball> ballList;  // initially null

void setup() {
  size(500, 500);

  // create the initially empty ArrayList of BouncingBall objects
  ballList = new ArrayList<BouncingBall>();

  // add 10 bouncing ball's
  ballList.add(Ball());
  ballList.add(Ball());
  ballList.add(Ball());
  ballList.add(Ball());
  ballList.add(Ball());
  ballList.add(Ball());
  ballList.add(Ball());
  ballList.add(Ball());
  ballList.add(Ball());
  ballList.add(Ball());
}

void draw() {
  background(255);

  // render and update all the balls
  for(BouncingBall b : ballList) {
    b.render();
    b.update();
  }
}

The problem here is that adding 10 ball’s requires calling ballList.add(Ball()) 10 times in a row. While this might be fine for 10 or so objects, if you wanted a couple of hundred balls then all these add statements become so numerous that they are extremely hard to manage.

A better approach is to use a while-loop:

// ...

int NUM_BALLS = 10;

void setup() {

   // ...

   int i = 0;
   while (i < NUM_BALLS) {
      ballList.add(Ball());
      i += 1;
   }

}

// ...

The while-loop not only greatly shortens the code, but also makes it trivial to change the number of balls by setting NUM_BALLS.

23.7. Questions

  1. What does each of the following code fragments print?

    int a = 5;                // fragment 1
    while (a <= 10) {
       println(a);
       ++a;
    }
    
    
    int a = 5;                // fragment 2
    while (a < 10) {
       println(a);
       ++a;
    
    
    int a = 5;                // fragment 3
    while (a <= 10) {
       ++a;
       println(a);
    }
    
    
    int a = 5;                // fragment 4
    while (a < 10) {
       ++a;
       println(a);
    }
    
    
    int a = 5;                // fragment 5
    while (a != 10) {
       println(a);
       ++a;
    }
    
    
    int a = 5;                // fragment 6
    while (a != 10) {
       ++a;
       println(a);
       ++a;
    }
  2. What does each of the following code fragments print?

    int k = 5;                // fragment 1
    while (k > 1) {
       println(k);
       --k;
    }
    
    
    int k = -1;               // fragment 2
    while (k > -5) {
       println(k);
       --k;
    }
    
    
    int k = -1;               // fragment 3
    while (k > -5) {
       --k;
       println(k);
    }
  3. What does each of the following code fragments print?

    int b = 0;                // fragment 1
    while (b < 10) {
       println(b);
       b += 2;
    }
    
    
    int b = 0;                // fragment 2
    while (b <= 10) {
       println(b);
       b += 2;
    }
    
    
    int b = -10;              // fragment 3
    while (b < 0) {
       println(b);
       b += 3;
    }
    
    
    int b = 10;               // fragment 4
    while (b >= 0) {
       println(b);
       b -= 2;
    }
    
    int b = 0;                // fragment 5
    while (b < 10) {
       println(b);
       b *= 2;
    }
    
    
    int b = 1;                // fragment 6
    while (b < 10) {
       println(b);
       b *= 2;
    }
  4. Write a file loop that prints the following sequences of numbers. There should be exactly one println statement in the body of your while loop that prints one number of the sequence on each iteration.

    1. 1, 2, 3, 4, 5
    2. 5, 4, 3, 2, 1
    3. -1, -2, -3, -4, -5
    4. -5, -4, -2, -1
    5. 1, 3, 5, 7, 9
    6. 9, 7, 5, 3, 1
    7. -5, 0, 5, 10, 15
    8. 1, 1, 2, 2, 3, 3, 4, 4 (remember that there should be exactly one println statement in the body of your while-loop that prints exactly one number of the sequence)
    9. 1, -1, 2, -2, 3, -3, 4, -4 (remember that there should be exactly one println statement in the body of your while-loop that prints exactly one number of the sequence)
    10. -1, 1, -2, 2, -3, 3, -4, 4 (remember that there should be exactly one println statement in the body of your while-loop that prints exactly one number of the sequence)