"Sputnik" help  
Sputnik Help
Generators

Description

Before reading this section make sure to read all User Functions and understand it.

This demonstrates how to create a function that supports the Yield and YieldFrom functions for the purpose of creating generators.

A generator function looks just like a normal function, except that instead of returning a value, a generator yields as many values as it needs to.

When a generator function is called, it returns a special Generator class that can be iterated over. When you iterate over that object (for instance, via a foreach loop), Sputnik will call the generator function each time it needs a value, then saves the state of the generator when the generator yields a value so that it can be resumed when the next value is required.

Once there are no more values to be yielded, then the generator function can simply exit, and the calling code continues just as if an array has run out of values.

It is important to note a generator function will exit a foreach loop immediately if the return value is a solid null so if the following statement would be true the generator would exit:

if ($value === null)
In this case $value would be the return value from your yield.

Remarks

Generators in Sputnik provide a powerful way to create iterable sequences of values using generator functions. A generator function is similar to a regular function, but instead of returning a value, it yields values one at a time as requested.

When a generator function is called, it returns a special Generator class object. This object can be iterated over, typically using a foreach loop. Each time the generator object is iterated, Sputnik calls the generator function, which yields the next value. The state of the generator is saved when a value is yielded, allowing the generator function to be resumed later when the next value is needed.

Generators are useful when dealing with large or infinite sequences of values, as they allow you to generate and process values on-the-fly without having to store them all in memory. This can lead to more efficient and scalable code.

The examples provided demonstrate the usage of generator functions. In the first example, the generator function Gen1To3() yields values from 1 to 3 in a foreach loop, printing each value. The generator function preserves the value of the variable $i between yields.

Sputnik also supports yielding key/value pairs in generators. The syntax for yielding a key/value pair is similar to defining an associative array. The second example, Gen1To3(), demonstrates yielding key/value pairs, where the keys are extracted from an array and the values are the corresponding indices.

Generator functions can yield values by reference as well. By yielding references, changes made to the referenced variables within the generator function are reflected outside the function. The third example, GenRef(), showcases yielding a reference to a variable, allowing modification of the referenced variable within the generator function.

Furthermore, it's worth noting that generator objects are created from a built-in Generator class. It is possible to access the raw functions of the Generator class to handle operations directly. The last example demonstrates using the GeneratorRewind(), GeneratorIsValid(), and GeneratorNext() functions of the generator object to retrieve and process values manually.

Generators provide a flexible and efficient way to generate sequences of values on-the-fly. By using generator functions and the iterable capabilities of the Generator class, you can create code that handles large datasets or infinite sequences with ease and efficiency.

Generators in are a powerful feature. They provide a convenient way to generate values on-the-fly without the need to precompute and store them in memory. Generators are particularly useful in scenarios where you need to work with large data sets or infinite sequences.

Some of the key benefits of generators include:

Overall, generators provide a flexible and efficient way to work with sequences of values, making your code more concise, memory-efficient, and adaptable to different scenarios.

Related

User Functions
Yield
YieldFrom

Example

A simple example of yielding values:
"g" function Gen1To3()
{
    for (my $i = 1; $i <= 3; $i++)
    {
        // Note that $i is preserved between yields.
        yield $i;
    }
}

$generator = Gen1To3();
foreach ($value in $generator)
    say "Value: " . $value;
// PRINTIS
// Value: 1
// Value: 2
// Value: 3

Sputnik also supports associative arrays, and generators are no different. In addition to yielding simple values, as shown above, you can also yield a key at the same time.

The syntax for yielding a key/value pair is very similar to that used to define an associative array, as shown below:

"g" function Gen1To3()
{
    my $animals = array("Cat", "Dog", "FoX");
    for (my $i = 0; $i <= 2; $i++)
    {
        // Note that $i is preserved between yields.
        yield $animals[$i] => $i;
    }
}

$generator = Gen1To3();
foreach (my $key => my $value in $generator)
    say "Key '$key' Value '$value'";
// PRINTIS
// Key 'Cat' Value '0'
// Key 'Dog' Value '1'
// Key 'FoX' Value '2'

Generator functions are able to yield values by reference as well as by value like so:

"g" function GenRef()
{
    $value = 3;
    while ($value > 0)
        yield &$value;
}
// Note that we can change $number within the loop, and
// because the generator is yielding references, $value
// within GenRef() changes.
foreach ($number in GenRef())
{
    say (*$number)-- . "... ";
}
// PRINTIS
// 3... 2... 1...

Here we used * to resolve the $number from a ref to an actual variable to modify the variable inside the generator function itself.

Since all Generators are created from a built in Generator class it is possible to access it's raw functions to handle the operation like so:

"g" function Gen1To3()
{
    my $animals = array("Cat", "Dog", "FoX");
    for (my $i = 0; $i <= 2; $i++)
        yield $animals[$i] => $i;
}

$generator = Gen1To3();
$generator->GeneratorRewind();
while ($generator->GeneratorIsValid())
{
    my $next = $generator->GeneratorNext();
    if ($next === null)
        continue;
    my List($key, $value) = KeyPair($next);
    say "Key '$key' Value '$value'";
}
// PRINTIS
// Key 'Cat' Value '0'
// Key 'Dog' Value '1'
// Key 'FoX' Value '2'

So there we used the classes functions directly to get the values.

Generators can be used to make infinite numbers in a range without having to create an array of these numbers like so:

"g" Function RangeGen($start, $end, $step = 1)
{
    for (my $i = $start; $i <= $end; $i += $step)
        yield $i;
}

foreach ($number in RangeGen(1, 10, 2))
{
    say $number;
}
// PRINTIS
// 1
// 3
// 5
// 7
// 9

This is similar to Range but without making the array.

Using a generator to generate padded numbers:

#define NextPaddedNumber() ($paddeNumberGen->GeneratorNext())

"g" Function PaddedNumberGen()
{
    for(my $i = 1; $i <= @Int64Max; $i++)
        yield StrPad($i, 3, "0", @StrPadLeft);
}

using (my $paddeNumberGen = PaddedNumberGen())
{
    $paddeNumberGen->GeneratorRewind();

    my $numbers = [];
    for(my $i = 1; $i <= 10; $i++)
        $numbers[] = NextPaddedNumber();
    printr $numbers;

    say NextPaddedNumber();
    say NextPaddedNumber();
    say NextPaddedNumber();
}

// PRINTS
// Array
// (
//     [0] => 001
//     [1] => 002
//     [2] => 003
//     [3] => 004
//     [4] => 005
//     [5] => 006
//     [6] => 007
//     [7] => 008
//     [8] => 009
//     [9] => 010
// )
// 011
// 012
// 013
// Value: 1
// Value: 2
// Value: 3

 


Contact
Cheryl (uberfox@hotmail.com)
Homepage
http://ubersoft.org