Generators¶
A generator is a coroutine which may return zero or more values.
Generator-functions are defined with usage of generator
keyword.
It’s possible to use operator yield
inside a generator, which is used for producing of a new value by the generator.
A value (or a reference) passed into yield
is returned to a code that calls this generator.
This operator is not terminal - execution is possible after it.
Generator-function with operator yield
usage:
fn generator GenNumbers() : i32
{
yield 1;
yield 2;
yield 3;
}
Low-level functionality of the yield
operator is the following: it fills result value, pauses generator execution and returns control flow to a generator caller.
A caller extracts the value produced by the yield
operator.
It’s also possible to use return
operator inside generators.
A retrun
operator without a value just finishes a generator.
A return
operator with a value is identical to a combination of yield
and empty return
.
If a generator function has no return
operator(s) it will be produced implicitly - at the end of the function, like for regular functions returning void
.
fn generator GenNumbers(bool cond) : i32
{
yield 1;
if( cond )
{
return;
}
else
{
return 2; // is equivalent to yield 2; return;
}
}
Generator call¶
Values are obtained from a generator with if_coro_advance operator.
Usually it is used in a loop, because many generators produce sequences of values.
If no control flow was transferred to a block of if_coro_advance
, means that a generator was finished.
Generator type¶
Generator type is a type of generator-objects. Generator functions return generator-type objects.
Ü has a special syntax for specifying of generator types.
It consists of generator
keyword, optional notation for inner references specification, optional non_sync
tag, return type (with/without reference modifier).
type IntGen= generator : i32; // Simplest generator
var [ [ char8, 2 ], 1 ] return_references[ "0a" ];
type FloatRefGen= generator'imut' : f32 & @(return_references); // A generator that returns a reference and stores references inside.
type NonSyncRefGen= generator'mut' non_sync : u64 &mut @(return_references); // non_sync generator that returns immutable reference and stores mutable references inside.
As it can be seen generator type isn’t strictly affected by the details of a specific generator-function (by which it was created). This allows to use the same variable for storing of generators produced by calls to different generator-functions - with different bodies and parameters.
// Generator-functions. Their return type is (generator : i32).
fn generator Foo(i32 x, i32 y) : i32;
fn generator Bar() : i32;
// A function which returns generator-object but which is not a generator-function.
fn CreateGen(bool cond) : (generator : i32)
{
return select(cond ? Foo( 14, 56 ) : Bar() );
}