getNext

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Mon Jul 12 21:38:55 PDT 2010


On 07/12/2010 11:21 PM, Jonathan M Davis wrote:
> On Monday 12 July 2010 20:48:05 Andrei Alexandrescu wrote:
>> I think I figured out a comfortable and all-encompassing means to define
>> a simplified interface for an input range.
>>
>> Currently input ranges need to define empty, front, and popFront. That
>> works but it's a bit heavy for simple input ranges. We've been
>> discussing simplified interfaces in this group but couldn't find one
>> that satisfied all use cases.
>>
>> Consider this:
>>
>> T* getNext(R, T)(ref R range, ref T item);
>>
>> Semantics: if the range wants to expose addresses of its elements, it
>> returns a pointer to the current element and also advances to the next
>> element. Otherwise (i.e. the range does not have or does not want to
>> expose addresses of its elements), the range fills "item" with the
>> current value, again moves on to the next value, and returns&item.
>>
>> In all cases, when there are no more elements in the range, getNext
>> returns null.
>>
>> getNext is easy to define for e.g. arrays and files. How does it sound?
>> Does it bring significant simplification?
>>
>>
>> Andrei
>
> What happens to empty, front, and popFront then? Is this a case where something
> must define either empty, front, and popFront or getNext to be an input range? Or
> is this something else? Personally, I find empty, front, and popFront quite
> useful and simple for anything that I've done, and I'd find getNext to be a lot
> more verbose. getNext may be great if you're using empty, front, and popFront
> pretty much simultaneously, but if you don't want to use all of them for
> whatever you're doing, then getNext is overkill.

An input range could either define the troika empty/front/popFront or 
getNext. In the former case, getNext detects the presence of the troika 
and uses it transparently. That's great because client code can simply 
use getNext throughout.

> So, essentially, I suppose the issue is that I don't see what you intend to do
> to front, popFront, and empty if you add getNext into the mix.

There is no aggravation brought to the current definitions.

> I do not want to
> see front, popFront, or empty go away. Having getNext as an additional function
> to make it easier to iterate over a range and do something with each element as
> you iterate wouldn't hurt my feelings any, but I definitely don't want to lose
> popFront, empty, or front.

My feelings too. The troika is here to stay, and definitely necessary 
for any range richer than an input range.

> As for simplification, it strikes me as more complicated in every case except
> where you are iterating over a range and processing each element as you iterate.
> Granted, that's a common use case, but there are plenty of other cases, where if
> you were forced to use getNext instead of having popFront, empty, and front,
> that would be a major problem.

Yah, truth be told getNext won't win a prize for brevity. You need to 
define both a variable and a pointer to use it:

T meh;
T * neh;
while ((neh = getNext(r, meh))) {
    ... process *neh ...
}

I've just had an idea that is so dark and devious, I was almost afraid 
to try it. But it works like a charm. Consider:

T * getNext(R, E)(ref R range,
                   ref E store = *(cast(E*) alloca(E.sizeof))
{
     ...
}

With this, allocating a dummy buffer on caller's stack is automated, so 
client code can just write:

for (T * p; (p = getNext(r)); )  {
    ... process *p ...
}

I feel dirty.


Andrei


More information about the Digitalmars-d mailing list