foreach vs. iterators
Benji Smith
dlanguage at benjismith.net
Fri Nov 3 17:14:23 PST 2006
Bill Baxter wrote:
> There's no way I can see to stop that juggernaut before it's done, short
> of having it return, and if it returns then it'll lose its state.
> Conceptually what you need is a 'yield' that keeps the current stack
> frame alive, but returns to the caller.
But then your object can only have one iterator at a time, and what if
you want to have multiple simultaneous iterators for any given object?
The 'yield' keyword can only keep track of state for a single iterator,
so this kind of code would fail:
foreach (Item outerItem; collection) {
foreach (Item innerItem; collection) {
doSomething(outerItem, innerItem);
}
}
This should be semantically identical to:
for (int i = 0; i < collection.length; i++) {
Item outerItem = collection[i];
for (int j = 0; j < collection.length; j++) {
Item innerItem = collection[j];
doSomething(outerItem, innerItem);
}
}
But in the 'foreach' example, the 'yield' implementation would get
confused (as would the opApply method).
If iteration was implemented with iterators (instead of with operator
overloading and delegates), and if iterators were implemented as nested
classes within the container class definitions, then iterators could
access the elements directly, while still keeping their own state
information. (Such as a pointer to the next iterable tree-node, in a
InOrderTraversalIterator. Or whatever.)
For example:
class ArrayList {
private Item[] items;
private Iterable getForwardIterator() { ... }
class ForwardIterator : Iterable {
private Item* nextItem; // Keeps track of state
public bool hasNext() { ... }
public Item next() { ... }
}
}
And then I'd iterate through my items like this:
foreach (Item outerItem; collection.getForwardIterator()) {
foreach (Item innerItem; collection.getForwardIterator()) {
doSomething(outerItem, innerItem);
}
}
In most cases, if your iterator can keep track of its own state, and if
the iterator is a nested class with access to all of its containing
class's members, then the 'yield' keyword is unnecessary.
(The most compelling argument for 'yield' is not for the implementation
of iterators, but for building generators.)
But please, please reconsider the foreach * foreach_reverse
implementations. Forcing a collection class to be aware of its own
iterables is fugly as can be.
--benji
More information about the Digitalmars-d-announce
mailing list