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