Iterators and the for statement

The for statement is an abstract mechanism to iterate over the elements of a container. It relies on an iterator to do so. Like while statements, for statements open an implicit block, so that they can be left with a break statement.

The for loop declares iteration variables - their scope reaches until the end of the loop body. The iteration variables’ types are inferred by the return type of the iterator.

An iterator is similar to a procedure, except that it can be called in the context of a for loop. Iterators provide a way to specify the iteration over an abstract type. A key role in the execution of a for loop plays the yield statement in the called iterator. Whenever a yield statement is reached the data is bound to the for loop variables and control continues in the body of the for loop. The iterator’s local variables and execution state are automatically saved between calls. Example:

  1. # this definition exists in the system module
  2. iterator items*(a: string): char {.inline.} =
  3. var i = 0
  4. while i < len(a):
  5. yield a[i]
  6. inc(i)
  7. for ch in items("hello world"): # `ch` is an iteration variable
  8. echo ch

The compiler generates code as if the programmer would have written this:

  1. var i = 0
  2. while i < len(a):
  3. var ch = a[i]
  4. echo ch
  5. inc(i)

If the iterator yields a tuple, there can be as many iteration variables as there are components in the tuple. The i’th iteration variable’s type is the type of the i’th component. In other words, implicit tuple unpacking in a for loop context is supported.