Iterators (Was: Re: Lazy eval -- an example issue)
Oskar Linde
oskar.lindeREM at OVEgmail.com
Fri Aug 25 06:54:20 PDT 2006
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).
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;
}
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.
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...
> About the only problem I had was inlining delegates
> passed to the functions, so the default operations are passed as structs
> with opCall defined instead.
I've encountered this too. Delegates passed to functions are often
called in tight inner loops. So far, I've never seen DMD doing a good
job at inlining those cases. Structs with opCall is an excellent idea,
that I will steal right away. :) It would be interesting to know if we
in the future can count on const delegates being inlined just as
efficiently.
/Oskar
More information about the Digitalmars-d
mailing list