Iterators (Was: Re: Lazy eval -- an example issue)

Chris Nicholson-Sauls ibisbasenji at gmail.com
Thu Aug 31 20:57:43 PDT 2006


Sean Kelly wrote:
> Oskar Linde wrote:
> 
>> Sean Kelly wrote:
>>
>>> Walter Bright wrote:
>>>
>>>>
>>>> I've struggled to get people to accept the {} version ever since D 
>>>> adopted anonymous delegates. Haven't made much headway in getting 
>>>> such used or in it having any sort of significant impact. How many 
>>>> have made a "dotimes(n, exp)" function or any sort of syntax 
>>>> extension using it? None that I've seen.
>>>
>>>
>>> I've been working on a predicate-oriented algorithm module on and off 
>>> for the past few weeks.  A few looping constructs have been left out 
>>> because foreach seems a preferable solution in D, but the rest is 
>>> coming along nicely.  
>>
>>
>> Interesting. I have been doing some of this myself too, but my 
>> available time has been limited.  I have also been looking at the 
>> concept of iterators. I agree that foreach is the preferable solution, 
>> but in some cases, only supporting foreach is too limited. For 
>> example, only using foreach, you can not iterate over two collections 
>> simultaneously.
>>
>> It would be great if we could come up with a standardized Iterator 
>> concept for D that supported both foreach style iteration (opApply) 
>> and some kind of single step iteration (maybe Java-style next/hasNext).
> 
> 
> I agree.  And given D's somewhat limited overloading mechanism, there 
> may simply be no point in trying to support pointers as iterators (ie. 
> to use traits templates).  This suggests that some sort of 
> self-contained design may be best, but I haven't thought about the issue 
> enough to comment on the details.
> 
>> Here is a sample of how it could look (but this particular sample 
>> seems to give a segfault on DMD 0.165 for some reason):
>>
>> template opApplyMixin() {
>>   int opApply(int delegate(inout ValueType v) dg) {
>>     ValueType *t;
>>     while(hasNext()) {
>>       t = next();
>>       if (auto status = dg(*t))
>>     return status;
>>     }
>>     return 0;
>>   }
>> }
>>
>> /// Simple array iterator wrapper
>> struct ArrayIterator(T) {
>>   T[] arr;
>>   alias T ValueType;
>>
>>   T* next() { T* r = arr.ptr; arr = arr[1..$]; return r; }
>>   bool hasNext() { return arr.length > 0; }
>>   mixin opApplyMixin;
>> }
> 
> 
> So this would cover unidirectional iterators (forward and reverse) but 
> not bidirectional iterators?  Perhaps we need a hasPrev as well?  And 
> then there's random access iterators...
> 
>> I have been looking at implementing many of my functional algorithms 
>> as array views/iterators. For example:
>>
>> foreach(word; read!(char)("file.txt").splitIterate(&isSpace)) {
>>     writefln("%s",word);
>> }
>>
>> where splitIterate is implemented just as the regular split, but 
>> instead of allocating and returning char[][] array, it is implemented 
>> as an iterator returning the next char[] slice for each iteration 
>> without allocating any extra data.
> 
> 
> I think Matthew played with this idea a bit in DTL, but I don't think he 
> got quite this far.  It's a great idea however.  I can't recall if he 
> had a name for it, but "view" seems to fit.
> 
>> read could probably be implemented in a smart way, reading the file a 
>> certain chunk at a time. Never using more than a constant amount of 
>> memory.
>>
>> Other functions as iterators I have been implementing are:
>>
>> split(array,predicate|substring|element)
>> select(array,predicate|element)
>> reverse(array)
>> range(start,stop,next)
>> generate(init,next)
>> map(array,func)
>> indexmap(array,indexarray|nextindexfunc)
>> and so on...
> 
> 
> That's a solid proof of concept :-)
> 
> 
> Sean

I still think a good move would be to allow delegates as foreach aggregates.  Then a class 
could expose "iterators" in the form of methods, and algorithms could be represented as 
member delegates.

-- Chris Nicholson-Sauls



More information about the Digitalmars-d mailing list