module Iterators {
import { /Std; }
// ITERATOR BASICS
// Iterators allow steping through a possibly infinite series of values.
//
// An iterator is a function that returns an optional value
// When the function returns none, there are no more values remaining
//
// typedef Iterator = fn{T}() : T?;
//
// Types that support iteration implement the Iterable interface.
// The iterate method of the Iterable interface returns an Iterator.
//
// interface Iterable{T} {
// iterate() : Iterator{T};
// }
//
// define Point structure
struct Point {
x : int;
y : int;
z : int;
}
// implement Iterable interface for Point
impl Iterable{int} {
// implement iterate method
iterate(this : Point) : Iterator{int} => {
// counter used to track which field to return (x, y, or z)
let i = 0;
// return iterator function that returns optional int
return fn() : int? => {
// check counter to determine what to return
let result = match (i) {
0 => this.x;
1 => this.y;
2 => this.z;
_ => none; // no more values
}
if (i < 3) {
i += 1;
}
return result;
}
}
}
fn test1() {
// create a point
let p = Point(1, 2, 3);
// step through values of p
for (val in p) {
print(val); // prints 1, 2, 3
}
// iterators can also be called manually
// the following is equivalent to the above for loop
let iterator = p::Iterable.iterate();
loop {
let next = iterator();
if (next) {
print(next!); // print value
} else {
break; // no more values, end loop
}
}
}
// USING YIELD TO IMPLEMENT ITERATORS
// use yield to help implement iterators, without having to define functions and maintain state
// • use yield{T} as the return type of the iterator function to signal that yield will be used
// • use yield to return each value from the iterator
// • use yield... to yield all items from an existing iterator
struct DoorMaterials {
knob : string;
frame: string;
panel: string;
hinges : string[];
}
// implement Iterable interface for DoorMaterials
impl Iterable{string} {
// implement iterate method using yield
iterate(this : DoorMaterials) : yield{string} => {
// yield each field
yield this.knob;
yield this.frame;
yield this.panel;
// yield all values in hinges
yield ...this.hinges;
}
}
fn test2() {
let parts = DoorMaterials(
knob: "steel",
frame: "iron",
panel: "wood",
hinges: ["brass", "brass", "brass"]
);
for (part in parts) {
print(part); // prints steel, iron, wood, brass, brass, brass
}
}
}