The Freya Programming Language

Yield statements

See also

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.

Syntax

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.

Two kinds of yields

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;
NoteNote
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.

See also

The Freya Programming Language
Statements
goto statements
loop statements
Iterators
Expressions