For-loops

Consider this turtle graphics program that draws a square:

Turtle t;

void setup() {
  size(500, 500);
  t = new Turtle();
  t.setColor(color(0, 255, 0));
  noLoop();  // only call draw() once
}

void draw() {
  background(255);
  square();
}

void square() {
  t.forward(100);
  t.right(90);
  t.forward(100);
  t.right(90);
  t.forward(100);
  t.right(90);
  t.forward(100);
  t.right(90);
}

square() could be re-written use a while-loop like this:

void square() {
  int i = 0;
  while (i < 4) {
    t.forward(100);
    t.right(90);
    i += 1;
  }
}

This function shows a common pattern of a while-loop usage. There is a single variable, i, that is initialized to 0 just before the loop. The while-loop condition checks the value of i, and then, at the bottom of the loop body, i is incremented by the statement i += 1.

Let’s re-write the loop to emphasize this pattern:

int i = 0;       // initialization
while (i < 4) {  // condition
    // ...
    i += 1;      // increment
}

The // ... part of the body could be many statements long, and so the the condition i < 4 and the increment i += 1 could be very far apart. This is a problem because they are logically quite closely related: they both are needed to control the loop itself.

So Processing (i.e. Java), provides an alternate form of the for-loop that puts the initialization, condition, and increment in one place at the top of the loop. The following for-loop is equivalent to the original while-loop from above:

for(int i = 0; i < 4; i += 1) {
    t.forward(100);
    t.right(90);
}

In this kind of for-loop, all the loop-control information is gathered into one place at the top of the loop. It’s easy to see the initial value of i, the condition, and how i is incremented.

Traditionally, instead of i += 1, for-loop use the ++ operator, e.g.:

for(int i = 0; i < 4; ++i) {  // ++i means "add 1 to i"
    t.forward(100);
    t.right(90);
}

In general, a for-loop has this form:

for(initialization; condition; increment) {
    // ... body code ...
}

Which is equivalent to this while-loop:

{
    initialization;
    while (condition) {
        // ... body code ...
        increment;
    }
}

for-loops can be confusing at first because they pack so much information into their first line. But once you understand that, they become easier to read and write. Some experienced programmers never use while-loop, and use for-loops exclusively.

Using a for-loop, we could re-write square once again:

void square() {
    for(int i = 0; i < 4; ++i) {
        t.forward(100);
        t.right(90);
    }
}

Here is a function that draws a regular polygon using a while-loop:

void polygon(int sides, int step) {
  int i = 0;
  while (i < sides) {
    t.forward(step);
    t.right(360.0 / sides);
    i += 1;
  }
}

And here’s an equivalent implementation that uses a for-loop:

void polygon(int sides, int step) {
    for(int i = 0; i < sides; ++i) {
        t.forward(step);
        t.right(360.0 / sides);
    }
}

The most important detail here is that the control information for the loop is in one place at the top. The body of the loop now contains just the code specific to the function.

For-each Loops as For-loops

Here is some code from the notes on particle systems:

void draw() {
  background(255);

  // render and update all the particles
  for (Particle p : particles) {
    p.render();
    p.update();
  }
}

particles is an ArrayList<Particle>, and contains sprites representing a particle system (such as the bits of an explosion).

A for-each loop is used here to access each element of particles, one at at time. This is often the simplest kind of loop to use, and so we try to use it whenever possible.

Let’s see how to re-write the loop first a while-loop, and then a for-loop. Here’s the while-loop version:

int i = 0;
while (i < particles.size()) {
    Particle p = particles.get(i);
    p.render();
    p.update();
    i += 1;
}

And the for-loop version:

for(int i = 0; i < particles.size(); ++i) {
    Particle p = particles.get(i);
    p.render();
    p.update();
}

Both are clearly more code than the original for-each loop, and a little harder to read. But they all do the same thing.

Example: Printing a Numbered List

Suppose you have a list of names in an ArrayList<String> object that you want to print as a numbered list, e.g.:

1. Marie
2. Ella
3. Ping
4. Meg

First, assume an ArrayList<String> called names has been declared like this:

ArrayList<String> names = new ArrayList<String>();
names.add("Marie");
names.add("Ella");
names.add("Ping");
names.add("Meg");

One way to do print the number list is to use a for-each loop:

int num = 1;
for (String s : names) {
  println(num + ". " + s);
  num += 1;
}

Or you could use a while-loop:

int i = 0;
while (i < names.size()) {
  String s = names.get(i);
  println((i + 1) + ". " + s);
  i += 1;
}

Notice that we’ve renamed num to i. That’s because its purpose is to serve as the index into names, and i is the traditional name for such a variable. Also different is that we’ve initialized i to 0 instead of 1. That’s because the first index location of an ArrayList is always 1. In the println the expression for printing the list item number is now i + 1 because, presumably, we want to start the list number at 1 (and not 0).

Or you could use a for-loop:

for (int i = 0; i < names.size(); ++i) {
  String s = names.get(i);
  println((i + 1) + ". " + s);
}

Again, we use a variable named i, starting at 0, since it’s purpose is to act as an index into names.

Which Loop to Use?

We’ve seen three kinds of loops in this course: while-loops, for-each loops, and for-loops.

Generally, for-each loops are the easiest to use, and so you should use them whenever possible. Unfortunately, they work when you are using a container object, such as an ArrayList.

So if you can’t use a for-each loop, plain for-loops are generally the next best choice. They are more flexible than for-each loops, and, as compared to a while-loop, are usually easier to read because their initialization, condition, and increment are all gathered together in the loop header.

While-loops are syntactically simpler than for-loops, and they can be good for loops that don’t follow the initialization/condition/increment pattern of a for-loop.

Note

Processing (Java) has one more kind of loop: a do-while loop. It is essentially a while-loop where the condition is test at the bottom of the loop instead of the top. For example, this code prints the numbers from 1 to 10:

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

Because the condition is checked at the bottom, the body of this loop is guaranteed to be executed at least once.

In practice, do/while are surprisingly rare. This seems to be because the requirement that the body of the loop be executed at least once is often not what is wanted. In many loops, it might be the case that the body is executed 0 times.

We won’t use do/while loops in this course. You can always re-write a do/while loop as an equivalent while-loop or for-loop.

Questions

  1. Write the general form of a for-loop.

  2. Why are for-loops often preferred over while-loops?

  3. Explain the difference between a for-each loop and a for-loop.

  4. Write a loop that prints all numbers from 1 to, and including, 1000 that are evenly divisible by 5. Do it in two different ways:

    1. Using a while-loop.
    2. Using a for-loop.
  5. Re-write the following while-loops as equivalent for-loops:

    //
    // A
    //
    int i = 0;
    while (i < 100) {
      println(i);
      i += 1;
    }
    
    //
    // B
    //
    int i = 100;
    while (i >= 0) {
      println(i);
      i -= 1;
    }
    
    //
    // C
    //
    int m = -5;
    while (i != 10) {
      println(i);
      i += 1;
    }
    
    //
    // D
    //
    int total = 1;
    int i = 0;
    while (i <= 100) {
      total += i * i;
      i += 1;
    }
    
  6. Re-write the following for-loops as equivalent while-loops:

    //
    // A
    //
    for(int i = 3; i < 100; ++i) {
      println(i - 5);
    }
    
    
    //
    // B
    //
    for(int i = 75; i > -100; i -= 2) {
      println(i);
    }
    
    //
    // C
    //
    int i = 3
    for(; i < 100; ++i) {
      println(i - 5);
    }
    
    //
    // D
    //
    for(;;) {
      println("cat");
    }
    

The Turtle Class

class Turtle {
  float x;
  float y;
  float angle;
  boolean penUp;
  color penColor;

  Turtle() {
    x = width / 2;
    y = height / 2;
    angle = 0.0;
    penUp = false;
    penColor = color(0);
  }

  void penDown() {
    penUp = false;
  }

  void penUp() {
    penUp = true;
  }

  void setColor(color c) {
    penColor = c;
  }

  void left(float degrees) {
    right(-degrees);
  }

  void right(float degrees) {
    angle += degrees;
  }

  void forward(float dist) {
    float dx = dist * cos(radians(angle));
    float dy = dist * sin(radians(angle));
    if (!penUp) {
      stroke(penColor);
      line(x, y, x + dx, y + dy);
    }
    x += dx;
    y += dy;
  }
} // class Turtle