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