3.3. Iterator Examples

Some of the following examples make use of arrays, which will be introduced in the chapter on Parametrized Classes

Because they are so useful, the 'while!', 'until!' and 'break!' iterators are built into the language. Here's how 'while!' could be written if it were not a primitive
while!(pred:BOOL) is
   -- Yields as long as 'pred' is true
   loop
      if pred then
         yield;
      else
         quit;
      end;
   end;
end;

The built-in class 'INT' defines some useful iterators. Here's the definition of 'upto!'. Unlike the argument 'pred' used above, 'i' here is declared to be 'once'; when 'upto!' is called, the argument is only evaluated once, the first time the iterator is called in the loop.
upto!(once i:SAME):SAME is
   -- Yield successive integers from self to `i' inclusive.
   r ::= self;
   loop
      until!(r > i);
      yield r;
      r := r + 1
   end;
end;

To add up the integers 1 through 10, one might say
sum:INT := 0;
loop
   sum := sum + 1.upto!(10);
end;

Or, using the library iterator 'sum!' like this. 'x' needs to be declared (but not initialized) outside the loop, so its value is available after the loop terminates.
x:INT;
loop
   x := INT::sum!(1.upto!(10));
end;

Some of the most common uses of iters are with container objects. Arrays, lists, sets, trees, strings, and vectors all have iterators to yield all their elements. Here we print all the elements of some container 'a'
a:ARRAY{INT} := |1,2,7|;
loop
   #OUT + a.elt!.str + '\n';
end;

This doubles the elements of array 'a'
loop
   a.set!(a.elt! * 2);
end;

This computes the dot product of two vectors 'a' and 'b'. There is also a built-in method 'dot' to do this. 'x' needs to be declared (but not initialized) before the loop.
loop
   x := sum!(a.elt! * b.elt!);
end;

Separating elements of a list

When printing out the elements of a container, or other kinds of lists, it is usually appropriate to insert a separator between all the elements (but, of course, not after the last element). There is a convenient iterator in the string class that does exactly this:.
a:ARRAY{INT} := |1,2,3|;
loop
   #OUT + ",".separate!(a.elt!.str);
end;
-- Prints out 1,2,3

The separate! iterator is called on the string which you wish to use to separate components of the list. In this case, the list elements will be separated by a comma. The definition of this iterator is as shown below
class STR is
   ...
   separate!(s: STR): STR is
      -- On the first iteration just outputs `s', on later iterations
      -- it outputs self followed by `s'.
      yield s.str;
      loop
         yield self + s.str;
      end;
   end;
   ...
end;

Note that the argument to the iterator is not a once argument, and will be evaluated each time the iterator is called.