Forward ranges in Phobos v2
Paul Backus
snarwin at gmail.com
Thu Nov 4 03:25:12 UTC 2021
On Wednesday, 3 November 2021 at 17:41:10 UTC, Andrei
Alexandrescu wrote:
> On 2021-11-03 12:18, Paul Backus wrote:
>> On Wednesday, 3 November 2021 at 15:40:41 UTC, Andrei
>> Alexandrescu wrote:
>>> On 2021-11-02 20:38, Paul Backus wrote:
>>>>
>>>> auto next(R)(ref R r)
>>>> if (isForwardRangeV2!R && isMutable!R)
>>>> {
>>>> alias E = ElementType!R;
>>>> if (r.empty)
>>>> return none!E();
>>>> else
>>>> {
>>>> auto result = some(r.head);
>>>> r = r.tail;
>>>> return result;
>>>> }
>>>> }
>>>
>>> OK, so the signature of next for all ranges is:
>>>
>>> Option!(ElementType!R) next(Range)(ref Range);
>>>
>>> Is that correct?
>>
>> More precisely, to use the Phobos convention:
>> `is(ReturnType!((Range r) => r.next) ==
>> Option!(ElementType!R))`.
>>
>> So, `next` could be a function, a @property, or a member
>> variable, and it does not necessarily require an lvalue to
>> call (just like `front` today).
>
> We've considered this way back when. I'm talking like 2006. It
> was like this:
>
> T next(Range)(ref Range r, ref bool done);
>
> The main problem is that iterating such a forward range would
> entail a copy of each element of the range. This is not
> scalable in general.
>
> This is a showstopper.
If we want to avoid copying, we can have `next` return a `Ref!T`
in the case where the forward range has lvalue elements:
struct Ref(T)
{
T* ptr;
ref inout(T) deref() inout
{
return *ptr;
}
alias deref this;
}
I've tested some simple uses of this wrapper on run.dlang.io, and
it seems like DIP 1000 is good enough to make it work in @safe
code.
If "returns either `T` or `Ref!T`" sounds like a suspect design
for an API, consider that it is basically the same thing as an
`auto ref` return value--just with the distinction between ref
and non-ref brought inside the type system.
More information about the Digitalmars-d
mailing list