Генераторы

Генераторы - это корутины, которые могут вернуть ноль или более значений. Функции-генераторы объявляются с использованием ключевого слова generator.

Внутри генераторов можно использовать оператор yield, который используется для порождения очередного значения генератором. Значение (или ссылка), переданные в yield, возвращаются вызывающему генератор коду. Оператор этот не терминальный - возможно продолжение исполнения кода после него.

Пример функции-генератора с оператором yield:

fn generator GenNumbers() : i32
{
    yield 1;
    yield 2;
    yield 3;
}

На низком уровне оператор yield заполняет результирующее значение и приостанавливает выполнение генератора, возвращая управление вызывающей стороне. Вызывающая сторона при этом извлекает значение, порождённое yield.

Внутри генераторов можно также использовать оператор return. Оператор return без значения просто переведёт генератор в завершённое состояние. Оператор return со значением аналогичен комбинации yield и пустого return. Если в функции-генераторе нету return, он будет порождён неявно - в конце функции, по аналогии с return для обычных функций, возвращающих void значение.

fn generator GenNumbers(bool cond) : i32
{
    yield 1;
    if( cond )
    {
        return;
    }
    else
    {
        return 2; // аналогично yield 2; return;
    }
}

Вызов генератора

Значения из генераторов извлекаются при помощи оператора if_coro_advance. Поскольку генераторы могут порождать целые последовательности значений, имеет смысл использовать этот оператор в цикле. Если же управление коду внутри оператора if_coro_advance передано не было, то это означает, что генератор завершился.

Тип генератора

Тип генератора - это тип объекта-генератора. Функции-генераторы возвращают объекты типа генератора.

В Ü существует специальный синтаксис для указания типа генератора. Состоит он из ключевого слова generator, опциональной нотации для указания внутренних ссылок, опционального non_sync тега, типа (с учётом ссылочности) возвращаемого значения.

type IntGen= generator : i32; // Простейший генератор
var [ [ char8, 2 ], 1 ] return_references[ "0a" ];
type FloatRefGen= generator'imut' : f32 & @(return_references); // Генератор, возвращающий ссылку и хранящий внутри себя ссылки.
type NonSyncRefGen= generator'mut' non_sync : u64 &mut @(return_references); // non_sync генератор, возвращающий изменяемую ссылку и хранящий внутри себя изменяемые ссылки.

Как можно заметить, тип генератора не определяется конкретными особенностями конкретного генератора (как он был создан). Это позволяет использовать одну и ту же переменную для хранения генераторов, порождённых разными функциями-генераторами с разным телом и разными параметрами.

// Функции-генераторы. Тип их возвращаемого значения - (generator : i32).
fn generator Foo(i32 x, i32 y) : i32;
fn generator Bar() : i32;
// Функция, возвращающая значения типа генератора, но не являющаяся генератором.
fn CreateGen(bool cond) : (generator : i32)
{
    return select(cond ? Foo( 14, 56 ) : Bar() );
}