Iterators

From RemObjects Software

Jump to: navigation, search

This is a Oxygene Language Feature topic
Feel free to add your notes to this topic below.


Iterators are an easy and comfortable way to implement customs sequences in your Oxygene project.

Iterators are special types of methods that return a sequence. When called, the body of the iterator method is not actually executed, but a new object is returned, representing the sequence. Once code starts to enumerate over the sequence, for example in a "for each" loop, the iterator's method body will be executed to provide the sequence elements.

A sample, as the saying goes, says more than a thousand words, so let's start by looking at a real live iterator implementation:

method MyClass.GetEvenNumbers: sequence of Int32; iterator;
begin
  for i: Int32 := 0 to 100 step 2 do
    yield i;
end;

That's a fairly simple iterator method that will provide a sequence of all even numbers between 0 and 100. Right from the start, you will notice two things in this code that you haven?t seen before:

Firstly, the method is marked with the "iterator" directive, indicating to the compiler that this is no ordinary method, but an iterator, and will get special treatment from the compiler as such.

Secondly, you will notice the use of the new "yield" keyword inside the "for" loop. This keyword is specific to iterator implementations, and used to pass back the individual elements of the sequence. You can think of this as the equivalent of "exit i", but instead of exiting the method, the value of i will be returned as part of the sequence, and the iterator will continue its work.

This is a lot to take in on first sight, so let's walk through what happens when this iterator is used in code such as this:

var Numbers := GetEvenNumbers();
for each n in Numbers do
  Console.WriteLine(n);

The first line calls our iterator method, but instead of executing any of the code we wrote in "GetEvenNumbers", this will simply create a new sequence object and pass it back, storing it in the "Numbers" variable. At this point, none of the "hard work" needed to calculate the sequence will be performed yet.

Next, we start our "for each" loop over the sequence, which in turn starts executing our iterator body. The "for" loop starts at 0, and reaches the "yield" keyword. At this point, the iterator will halt, and the first value, zero is passed pack, as the first element of the sequence. The body of the "for each" loop now executes with n = 0, and writes that value out to the console.

As the "for each" loop resumes, it will try to get the next value of the sequence ? which in turn resumes our iterator body. The "for" loop continues to i = 2, and the game continues.

Eventually, the iterator will reach 100, and exit - the end of the sequence has been reached, and the "for each" loop too will terminate.

As you can see with this simple example, iterators can make it very easy to implement complex sequences, by allowing the entire buildup of the sequence to be written as normal sequential code. Beyond what is shown in this sample, iterators can contain "yield" statements in various places, contain nested loops, conditions and almost all of the Oxygene language constructs that you can use in ordinary methods. This allows them to perform operations that would be very complex to achieve if every iteration of the sequence would need to be encapsulated independently.

Delegating Iteration to a Sequence

New in Oxygene 3.0.13, the yield keyword has been extended to support delegation of the iterator to a second sequence, as shown below:

var MoreValues := [3,4,5,6]; // array of Int32, can act as sequence

method MyIterator: sequence of Int32;
begin
  yield 1; // adds "1" to the sequence
  yield 2; // adds "2" to the sequence
  yield MoreValues; // adds "3" thru "6" to the sequence
  yield 7; // adds "7" to the sequence
end;

Limitations inside Iterator Methods

Since yielding in an iterator returns back to the caller, it's not possible to yield from within a protected block like locking or try/ finally, as there is no guarantee that the caller will call MoveNext again.

See Also


Product: RemObjects Oxygene (formerly known as Chrome)
Current version: 3.0 Previous Versions: 'Joyride' (2.0), 'Floorshow' (1.5), 'Adrenochrome' (1.0)

GlossaryKeywordsLanguage FeaturesPlatform FeaturesSamplesArticlesHow ToIssues

Personal tools