Consider the following example:
let iter = f();
for (i in iter)
break;
print(iter.next())
where f is defined as:
function f() { return ["a","b"].iterator::get(true); }
According to the current spec, it should print 1, the index of the second array element as the specs expands the for-in loop to:
let ($it = iter.iterator::get(true)) {
while (true) {
try {
i = $it.next();
} catch (e : iterator::StopIterationClass) {
break;
}
break;
}
}
or, assuming that iter defines iterator::get to return itself:
while (true) {
try {
i = iter.next();
} catch (e : iterator::StopIterationClass) {
break;
}
break;
}
Now consider the same example but define f() as a generator:
function f() { yield 0; yield 1; }
According to the proposal, this time the example throws iterator::StopIterationClass? at "print(iter.next())" as the new for-in loops expands as:
try {
while (true) {
try {
i = iter.next();
} catch (e : iterator::StopIterationClass) {
break;
}
break;
}
} finally {
iter.close();
}
This unconditionally closes the iterator.
Thus to remove this discrepancy I propose to add the close method to the IteratorType?:
type IteratorType.<T> = {
next: function () : T;
close: function () : void
};
and always define for (i in o) body as:
let ($it = iter.iterator::get(true)) {
try {
while (true) {
try {
i = $it.next();
} catch (e : iterator::StopIterationClass) {
break;
}
body
}
} finally {
$it.close();
}
}
The close method will also allow for a script to explicitly close the iterator releasing its resources if the script needs to code the iterations explicitly instead of using for-in loop.