Pyro

A dynamically-typed, garbage-collected scripting language.

Version 0.19.2

Iterators


Pyro's for loop uses a simple iterator protocol for iterating over sequences of values, e.g.

for item in [123, 456, 789] {
    echo item;
}

An object is iterable if it has an :$iter() method. This method should return an iterator — i.e. an object with a :$next() method that returns either the next item from a sequence or an err if the sequence has been exhausted.

Most of Pyro's builtin container types — e.g. vec, tup, map, etc. — are iterable. You can find a tutorial on implementing the iterator protocol for custom types here.

Example

We can illustrate the iterator protocol by creating a custom Range object to iterate over a range of integers:

class Range {
    var next = 0;
    var stop;

    def $init(stop) {
        self.stop = stop;
    }

    def $iter() {
        return self;
    }

    def $next() {
        if self.next < self.stop {
            self.next += 1;
            return self.next - 1;
        }
        return $err();
    }
}

Note that in this case the :$iter() method simply returns self — i.e. a Range instance is its own iterator.

We can try out our new Range type like this:

for i in Range(5) {
    echo i;
}

This gives us the following output:

0
1
2
3
4

(In practice, you don't need to implement this functionality yourself — Pyro already has a builtin $range() function that returns an iterator over a range of integers.)

Iterator Wrappers

Pyro has a builtin function called $iter() that can wrap any iterator in a special iter type that automatically adds support for a set of chainable, lazily-evaluated utility methods.

We can try it out on our custom Range type. First, let's define some callback functions:

def is_even(n) {
    return n % 2 == 0;
}

def square(n) {
    return n * n;
}

Now we can apply them using :filter() and :map():

for i in $iter(Range(10)):filter(is_even):map(square) {
    echo i;
}

This gives us the following output:

0
4
16
36
64

All the iterators returned by Pyro's builtin types and functions come pre-wrapped in iter wrappers so we could get an identical result using the builtin $range() function without needing to call $iter():

for i in $range(10):filter(is_even):map(square) {
    echo i;
}

You can learn more about iterator wrappers here.