Iterators

Warning

Iterators are not yet fully implemented (not even close).

Use for loops to iterate over iterators, or call their next() method to get the next item.

Use iterator instead of func to make a function or method an iterator.

Use yield to yield items from the iterator. return is not allowed in iterators.

Call iter() to create an iterator from classes that implements __iter__(). for-loops does this automatically.

Iterators implements the builtin generic trait Iterator[T], where T is the type of the items produced by the iterator.

The builtin generic iterator trait looks like this:

@generic(T)
trait Iterator:

    func next(self) -> T?
        pass

Fibonacci example

fibonaccis() is an iterator that yields count number of fibonacci numbers.

iterator fibonaccis(count: i64) -> (i64, i64):
    curr = 0
    next = 1

    for i in range(count):
        yield (i, curr)

        temp = curr
        curr = next
        next += temp

func main():
    for index, number in fibonaccis(10):
        print(f"fibonacci({index}): {number}")

The output is:

 mys run
 Reading package configuration (0 seconds)
 Building (0.01 seconds)
fibonacci(0): 0
fibonacci(1): 1
fibonacci(2): 1
fibonacci(3): 2
fibonacci(4): 3
fibonacci(5): 5
fibonacci(6): 8
fibonacci(7): 13
fibonacci(8): 21
fibonacci(9): 34

An iterator method example

chunks() is an iterator method that yields chunks of size bytes.

class Memory:
    data: bytes

    iterator chunks(self, size: i64) -> bytes:
        for offset in range(0, data.length(), size):
            yield self.data[offset:offset + size]

    iterator __iter__(self) -> u8:
        for value in self.data:
            yield value

func main():
    print("Chunks:")

    for chunk in Memory(b"123456789").chunks(4):
        print(chunk)

    print()
    print("Default iterator:")

    for byte in Memory(b"0123"):
        print(byte)

    print()
    print("Next method:")

    it = iter(Memory(b"0123"))
    print(it.next())
    print(it.next())
    print(it.next())
    print(it.next())
    print(it.next())
    print(it.next())

The output is:

 mys run
 Reading package configuration (0 seconds)
 Building (0.01 seconds)
Chunks:
b"\x31\x32\x33\x34"
b"\x35\x36\x37\x38"
b"\x39"

Default iterator:
0
1
2
3

Next method:
0
1
2
3
None
None

Iterator type example

func call(numbers: Iterator[string]):
    print("Calling:")

    for number in numbers:
        print(number)

func main():
    numbers = ["0702293884", "0769912312", "0709957734"]
    call(numbers)
    call(iter(numbers))
    it = iter(numbers)
    it.next()
    call(it)

The output is:

 mys run
 Reading package configuration (0 seconds)
 Building (0.01 seconds)
Calling:
0702293884
0769912312
0709957734
Calling:
0702293884
0769912312
0709957734
Calling:
0769912312
0709957734

Explicitly implementing the iterator trait

class MyIterator(Iterator[i64]):
    _a: i64
    _b: i64
    _c: i64
    _next_letter: char

    func __init__(self):
        self._a = 5
        self._b = 3
        self._c = 1
        self._next_letter = 'a'

    func next(self) -> i64?:
        match self._next_letter:
            case 'a':
                self._next_letter = 'b'

                return self._a
            case 'b':
                self._next_letter = 'c'

                return self._b
            case 'c':
                self._next_letter = ''

                return self._c
            case _:
                return None

func main():
    for item in MyIterator():
        print(item)

The output is:

 mys run
 Reading package configuration (0 seconds)
 Building (0.01 seconds)
5
3
1