Iterator straw-man
Bill Baxter
dnewsgroup at billbaxter.com
Tue Nov 7 18:25:34 PST 2006
Sean Kelly wrote:
I mostly agree with you. But have some comments on the specifics.
> What follows is a rough description of a "smart" read-only iterator for D:
>
> interface Iterator<T>
> {
> bool atEnd();
> T next();
> T curr();
> int opApply( int delegate( T ) dg );
> }
>
> The nuances are unimportant, but the basic idea is that any such
> iterator should provide a means of advancing, testing whether the
> iterator references a valid element, and of referencing that element.
> Also, opApply is supported to allow iterators to be used in foreach
> operations for simple uses.
I don't think opApply should be the mechanism by which foreach accepts
iterators. It's just too convoluted and too much a burden on iterator
implementors. And it's not going to be as efficient as a raw for-loop,
either.
> Assuming such a design, the iterator type determines progress through
> the container (forward, reverse, stepped, etc) rather than the algorithm
> being applied. Here is a straightforward implementation of some
> algorithms using such iterators, 'C' is a container type for demonstration:
>
> bool contains( C cont, E match ) {
> foreach( e; cont ) {
> if( e == match )
> return true;
> }
> return false;
> }
It should be possible to make a template out of that, too.
bool contains(C,E)( C cont, E match ) {
foreach( e; cont ) {
if( e == match )
return true;
}
return false;
}
Current compiler limitations aside, that *should* be reducible to the
same efficiency as a for loop with simple pointer (or index) manipulation.
> [...]
>
> Given the above, it seems awkward that the iterator must be declared
> outside of foreach so a copy may be made to return the position of the
> found element. Therefore, foreach should allow an arbitrary key type to
> be returned by opApply.
I like that. It makes sense. The iterator itself is analogous to the
int index when foreach-ing arrays. That seems very logical.
Given that similarity it seems like it would make sense for indexing a
container by an iterator to work as well:
foreach( i, e; cont.fwdIt ) {
if( e == match ) {
writefln("Matched item ", cont[i]);
return i;
}
}
I.e. cont[i] becomes synonymous with i.curr().
That would be easy to arrange if opIndex was allowed to take an iterator
as the index. (I think it's a good idea to remove the restriction on
opIndex arguments in any event, but this is another justification.)
An opIndex for an iterator would take the simple form:
static T opIndex(ContIterator i) { return i.curr(); }
If you had write-able iterator with say a .set(T v) method, then you
could also have opIndexAssign:
static T opIndexAssign(ContIterator i, T x) { return i.set(x); }
If the Iterator type has a pointer to its container, you could make the
methods non-static and assert(this==i.container).
> As an aside, foreach_reverse may remain useful in instances where we
> want the index of the current element instead of an iterator. Or array
> iterators may provide a means to obtain the relevant index. Perhaps
> someone could make an argument for or against based on these ideas.
foreach_reverse(i,x; cont) would remain (marginally) useful as a
shortcut for the special reverse iterator name: I.e. a synonym for
foreach(i,x; cont.revIter)
I'm guessing the specially-ordained iterator method names will probably
end up being opIter and opIterReverse (or maybe same with 'Iterator'
spelled out) just following the pattern established so far.
--bb
More information about the Digitalmars-d
mailing list