Skip to content

Iterators

One feature that was added in Xojo 2014r3 that I haven’t seen much discussion about yet is iterators. In short, iterators are a way to make classes useable with the existing For Each loop feature.

With the new framework, we’ve taken the opportunity to make several built-in classes iterable. For example, each character in a Text value can be accessed like so:

Dim myText As Text = "Hello world"
For Each char As Text In myText
  Xojo.System.DebugLog(char)
Next

There are two class interfaces involved with iterators: Xojo.Core.Iterator and Xojo.Core.Iterable. Iterators are responsible for providing the values used by the For Each loop. Iterable objects are responsible for creating the iterators. Here are the interface declarations:

Interface Iterator
  Function MoveNext() As Boolean
  Function Value() As Auto
End Interface
Interface Iterable
  Function GetIterator() As Iterator
End Interface

At the beginning of the for loop, the iterable is asked to create an iterator via GetIterator. Next the loop invokes MoveNext on the iterator, which positions the iterator at its first item. Then the Value function is invoked in order to get the value to be assigned to the variable in the for loop. This process of MoveNext/Value is repeated until the iterator returns False from MoveNext to indicate that it has no more items.

As a simple example, we’ll create a range class that works with For Each loops. We’ll start with a simple class that isn’t iterable:

Class MyRange
  Sub Constructor(minValue As Integer, maxValue As Integer)
    Self.MinValue = minValue
    Self.MaxValue = maxValue
  End Sub
  Dim MinValue As Integer
  Dim MaxValue As Integer
End Class

Next we’ll create the iterator class:

Class MyRangeIterator
  Implements Xojo.Core.Iterator

  Sub Constructor(minValue As Integer, maxValue As Integer)
    mValue = minValue - 1
    mMaxValue = maxValue
  End Sub
  Function MoveNext() As Boolean
    If mValue >= mMaxValue Then Return False
    mValue = mValue + 1
    Return True
  End Function
  Function Value() As Auto
    Return mValue
  End Function
  Private Dim mValue As Integer
  Private Dim mMaxValue As Integer
End Class

One important thing worth pointing out here is that the RangeIterator’s constructor sets mValue to the minimum value minus one. This is because iterators start out referencing the item ‘before’ the first item. This is to say that the first call to MoveNext positions the iterator at the first item, allowing MoveNext to return False to indicate that it has no items.

Finally we’ll go back and implement the Iterable interface on our Range class:

Class MyRange
  Implements Xojo.Core.Iterable
  Sub Constructor(minValue As Integer, maxValue As Integer)
    Self.MinValue = minValue
    Self.MaxValue = maxValue
  End Sub
  Function GetIterator() As Xojo.Core.Iterable
    Return New MyRangeIterator(MinValue, MaxValue)
  End Function
  Dim MinValue As Integer
  Dim MaxValue As Integer
End Class

Our range class can now be used with For Each loops:

For Each i As Integer In New MyRange(100, 105)
  Xojo.System.DebugLog(i.ToText)
Next


Watch Iterators Video