Assume a third-party API of the following signature:

    T* next(I iter);

which advances an iterator of sorts and returns the next element, or null when iteration is done. No other information about the state of the iterator is available.

I wish to adapt this interface to a forward range for use with foreach and Phobos' range utilities. This amounts to implementing empty, front, and popFront, in terms of next and some state. But there is a choice to be made regarding the first call to next.

One could call next during range construction:

    struct Range
    {
        private I iter;
        private T* current;
        this(I iter) { this.iter = iter; current = next(iter); }
        bool empty() const => current is null;
        inout(T)* front() inout => current;
        void popFront() { current = next(iter); }
    }

Or do not call it until the first call to empty:

    struct Range
    {
        private bool initialized;
        private I iter;
        private T* current;
        this(I iter) { this.iter = iter; }
        bool empty()
        {
            if (!initialized) {
                current = next(iter);
                initialized = true;
            }
            return current is null;
        }
        inout(T)* front() inout => current;
        void popFront() { current = next(iter); }
    }

The first implementation has the advantage is being simpler and empty being const, but has the downside that next is called even if the range ends up not being used. Is either approach used consistently across the D ecosystem?

Reply via email to