Iterator straw-man

Sean Kelly sean at f4.ca
Wed Nov 8 09:00:37 PST 2006


Bill Baxter wrote:
> 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.

True enough.  I mostly added it as an alternative for situations where 
users didn't need the power of a manual loop.  And I think 
implementation would be pretty simple for most/all iterators:

     for( ; !atEnd(); next() )
     {
         ret = dg( curr() );
         // handle ret
     }

>> 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.

Yup.  The function above was meant for illustrating an idea more than it 
was a proposal for how to implement a contains function :-)

>> [...]
>> 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().

Hrm, good point.

> 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.)

Is it currently required to be an integer?  I had no idea.

> 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).

All good ideas.

>> 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)

True enough.

> 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.

Following the D convention, the 'op' prefix suggests a use form 
different from that of a normal function call.  Personally, I'd be fine 
with this done as plain old property methods: fwdIt/revIt, or something 
along those lines.


Sean



More information about the Digitalmars-d mailing list