foreach vs. iterators

Chris Nicholson-Sauls ibisbasenji at gmail.com
Fri Nov 3 06:29:38 PST 2006


Bill Baxter wrote:
> Sean Kelly wrote:
> 
>> Walter Bright wrote:
>>
>>> Sean Kelly wrote:
>>>
>>>> I think I agree, but for the sake of argument, how would D handle 
>>>> 'find'  operations on sequences that don't support opIndex?  At some 
>>>> point, a generalizable bookmark is almost necessary for a faithful 
>>>> implementation of some C++ algorithms.  Also, many of these 
>>>> algorithms also require iteration across two sequences 
>>>> simultaneously, which doesn't map very cleanly into foreach.  
>>>> Consider a substring-style find operation (std::search), for 
>>>> example, where both the pattern and target types do not support 
>>>> opIndex or opSlice.  I might argue that it's a bit silly or 
>>>> unrealistic to desire such an operation, but the C++ algorithm 
>>>> library does support it.
>>>
>>>
>>>
>>> I think the target types will have to support opIndex or opSlice.
>>
>>
>>
>> Forgive me for resurrecting a horribly battered equine, but I was 
>> thinking about this a bit tonight and I've decided that foreach, 
>> foreach_reverse, and array operations are not a sufficient general 
>> substitute for C++ iterators.
>>
>> For example, let's say I want to compute the set union of two sorted 
>> ranges, one of size M, the other of size N.  By iterating across the 
>> two ranges simultaneously is is easy to see that the complexity for 
>> the operation will be max(M,N).  In C++ this is easily accomplished 
>> using forward iterators, and the ranges can be anything from arrays to 
>> SQL result sets.
>>
>> In D however, there is no way to iterate across multiple ranges 
>> simultaneously using foreach, so opIndex must be used instead.  With 
>> containers that have a constant-time lookup cost this isn't a big 
>> deal, but what if these containers are binary trees?  The complexity 
>> for such an operation would be M(log(M)) + N(log(N)).
>>
>>  From this it seems clear that foreach is not sufficiently adaptable 
>> to meet the needs of all sequential algorithms and opIndex is not a 
>> reasonable substitute for all cases where foreach may not be used.  
>> What alternatives do we have?  So far, iterator variants are all I've 
>> been able to come up with.
> 
> 
> It would be sufficient if D had coroutines and opApply were implemented 
> using them.
> 
> The problem is that once you call an opApply function right now, it has 
> to run to completion.  The only way I can see to have multiple opApply 
> style iterators going simultaneously if you could truly suspend 
> execution of one opApply temporarily and run another one for an iteration.
> 
> In other words, if you're going to use the stack and function state to 
> store iterator state, then the only way to have multiple iterators in 
> different states simultaneously is to be able to have multiple stacks 
> active simultaneously, aka coroutines.
> 
> --bb

Just a thought I had.  Would it be possible to emulate this behavior with 
delegate-as-aggregate?  What I'm thinking of (and bear in mind I just rolled out of bed, 
so I'm at quarter-speed right now ;)) is pass foreach a "driver" delegate that then calls 
step iterator delegates you've provided.  The driver and step iterators would be 
responsible for maintaining state, and would probably need a reset case (at least the 
iterators).

-- Chris Nicholson-Sauls



More information about the Digitalmars-d-announce mailing list