ListsTopFor loops

For loops

Many programs with while loops follow the same pattern. Here is an example from our flag program:

    var stripeNum: Number := 1
    var stripeStart: Point := point               //**
    while{stripeNum <= n} do {                  //**
      def redStripe:Graphic2D = 
          filledRect.at(stripeStart)size(width, stripeHeight) on (canvas)
      redStripe.color := red
      stripeNum := stripeNum + 1               //**
      stripeStart := stripeStart + (0@(2 * stripeHeight))
    }

In these, we have a counter (in this case stripeNum) that gets initialized before the loop and then increased by one every time through the loop until we reach the maximum value. Most programming languages include a construct that allows you to write this very common form in a simpler way. Here is the way we write it in Grace.

    var stripeStart: Point := point
    for(1 .. n) do { stripeNum: Number -> 
      def redStripe:Graphic2D = 
          filledRect.at(stripeStart)size(width, stripeHeight) on (canvas)
      redStripe.color := red
      stripeStart := stripeStart + (0@(2 * stripeHeight))
    }

In the above, the term 1..n stands for a list containing all the elements from 1 to n in that order. Using this in the for loop means that we will be going through the values 1, 2, ..., n as we go through the loop body. Just as before, stripeNum will start at 1, and then increase by 1 every time through the loop, and then the loop will terminate when stripeNum exceeds n. The three lines in the original version that are marked with //** are replaced by the single line for(... in the new version. The nice thing about this is that it makes it harder to forget to do important things like initialize the variable or increase it by one each time through the loop.

The best way of think about how the for loop works is to consider that the for loop will provide to the loop body a new number each time through the loop. That number will be associated with whatever identifier name has been provided before the arrow. (It is an error if you leave the identifier and arrow off the for loop.) The loop body is essentially the same kind of action as we associated with GUI components. The main difference is that we evaluated them with the successive elements of the list rather than with events generated by the user interacting with the GUI components.

Notice that the list 1..n is surrounded by parentheses rather than curly braces. This is because that term is evaluated exactly once, when you enter the for loop the first time. For example, what will be printed by the following

var n: Number := 10
for(1..n) do {index: Number ->
  print(index)
  n := n-1
}

You might think only the numbers from 1 to 5 would be printed, but in fact all of 1 to 10 will be printed. When the for loop is entered, the value of n is 10, so the list taken is the list of numbers from 1 to 10. Changing the value of n after we have started the loop has no impact.

Finally, remember that you can iterate over any range you want. They are great when you know exactly how many times you want to execute a loop body.


ListsTopFor loops