Iterators use the yield statement to return momentarily the instruction flow to the calling loop, while assigning a value to the control variable from the loop.
yield statements are only allowed inside an iterator. They have the following syntax:
yield expression
This statement cannot be included in a finally clause. You can use yield inside the try clause from a try/finally statement, but not inside try/except or try/fault statements. Note that this requirement is stronger than the corresponding requirements for goto statements.
There are two kinds of yield statements, according to the type of the yield expression. In the most common case, the yield expression type is the same as the return value from the iterator:
items: Array[Integer]; iterator GetItems: Integer; begin for var i := Count - 1 downto 0 do yield items[i]; end;
In the above example, both the iterator and the yield statement return an integer value. In this case, the yield statement stops the coroutine, returning to the calling loop and assigning a single value to the control variable.
In the other variant, yield is associated with an IEnumerable expression. This use is better explained with a recursive iterator:
BinaryTree[X].Node = class public property Value: X; property Left, Right: Node; // ... iterator PreOrder: X; begin yield Value; if Left <> nil then yield Left.PreOrder; if Right <> nil then yield Right.PreOrder; end; end;
There are three yield's in the previous iterator. The first one is associated with an expression with the same type as the return type of the iterator, so this is the simplest variant. The other two statements apparently returns a full sequence of X values. Actually, they are expanded as for/in statements. The iterator is translated like this:
iterator PreOrder: X; begin yield Value; if Left <> nil then for var v in Left.PreOrder do yield v; if Right <> nil then for var v in Right.PreOrder do yield v; end;
Note |
---|
Recursive iterators are not a good idea, if you can avoid them. Each nested iteration will create a temporal instance of a IEnumerable compiler generated class. However, most of the times the recursive version is clearer and easier to write and maintain than the non recursive variant. Basically, you're trading space and some speed for clarity. Despite of this warning, the second yield variant is still useful for creating new iterators from existing iterators. |
The Freya Programming Language
Statements
goto statements
loop statements
Iterators
Expressions