Ranges and/versus iterators

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Tue Mar 23 13:51:48 PDT 2010


On 03/23/2010 03:46 PM, Steven Schveighoffer wrote:
> On Tue, 23 Mar 2010 16:34:24 -0400, Andrei Alexandrescu
> <SeeWebsiteForEmail at erdani.org> wrote:
>
>> On 03/23/2010 02:45 PM, Fawzi Mohamed wrote:
>>> Andrei, as the topic just came up a comment on the range interface.
>>> Just for plain forward iterators iterators having
>>>
>>> bool empty()
>>> E front()
>>> void popFront()
>>>
>>> makes the interface non reentrant.
>>> For that purpose having a single function is better.
>>> I use
>>>
>>> bool popFront(ref T t)
>>> // returns true if there is a next element, and in that case returns it
>>> in t
>>>
>>> this can be used by several consumers concurrently without problems and
>>> creating filters, combiners,... is simple.
>>> Another advantage is that a single object can implement several
>>> iterators.
>>> A disadvantage is that even if there is a single iterator D makes type
>>> inference cumbersome, i.e. you cannot simply use auto, as in a loop you
>>> have to declare the variable before using it as the loop is
>>> T a;
>>> while (it.popFront(a)){
>>> //...
>>> }
>>
>> We've discussed this extensively, and I lost sleep over this simple
>> matter more than once. The main problem with bool popFront(ref E) is
>> that it doesn't work meaningfully for containers that expose
>> references to their elements.
>>
>> The interface with front() leaves it to the range to return E or ref E.
>>
>> An alternative is this:
>>
>> bool empty();
>> ref E getNext(); // ref or no ref
>>
>> I'm thinking seriously of defining input ranges that way. The
>> underlying notion is that you always move forward - getting an element
>> is simultaneous with moving to the next.
>
> A while back, you identified one of the best interfaces for input ranges:
>
> E* getNext();
>
> Which allows for null returns when no data is left. The drawback is that
> E must be either referenced or allocated on the heap (providing storage
> to the function is an option). But the killer issue was that safeD would
> not allow it. However, in recent times, you have hinted that safeD may
> allow pointers, but disallow bad pointer operations. In light of this,
> can we reconsider this interface, or other alternatives using pointers?
>
> I've always felt that if we were to define ranges for streams in a
> non-awkward way, we would need an "all in one" operation, since not only
> does getting data from the range move the range, but checking for empty
> might also move the range (empty on a stream means you tried to read and
> got nothing).

I'd gladly reconsider E* getNext(), and I like it a lot, but that 
doesn't accommodate ranges that want to return rvalues without storing 
them (e.g. a range using getchar() as a back-end, and generally streams 
that don't correspond to stuff stored in memory). If it's not in memory, 
there's no pointer to it.


Andrei



More information about the Digitalmars-d mailing list