Iterators for D

Burton Radons burton-radons at smocky.com
Fri Nov 10 09:04:25 PST 2006


I don't like C++ iterators; they're a very old design made to fit a 
language that was unmodifiable. They can't work with destructive or 
unbound iterators (well, they can, but you just gotta hope to hell the 
user doesn't use the interface in an unusual way), they can't work with 
associative arrays or tree structures without allocation (or wasting 
space in the structure for parent node pointers), and they're VERY 
verbose and distributed. Plus they allow iterating to an illegal index 
(the end index), which requires an additional state value for some 
iterables.

Python's generators are a far better solution, like:

    void i_range (T) (T from, T to, T step = cast (T) 1, yield T index)
    {
        for (index = from; index < to; index += step)
            yield;
    }

    foreach (i; i_range (0, 100)) ...

Or:

    yield T i_range (T) (T from, T to, T step = cast (T) 1)
    {
        T index;

        for (index = from; index < to; index += step)
            yield index;
    }

You've been meaning to allow frame pointers for proper closures anyway, 
right? :P

The implementation in iterators using the simplest interface I can think 
of would be something like:

    struct IRange (T, T from, T to, T step = cast (T) 1)
    {
        T index = from;

        static IRange opCall (T value)
        {
            IRange result;

            result.index = value;
            return result;
        }

        T opThis ()
        {
            return index;
        }

        IRange opNext ()
        {
            assert (index <= end);
            return opCall (index + 1);
        }

        IRange opEnd ()
        {
            return opCall (to);
        }
    }

    foreach (i; IRange! (int, 0, 100)) ...

Notice how the SINGLE line indicating how the arguments are interpreted 
are hidden within a whole bunch of boilerplate.



More information about the Digitalmars-d mailing list