opIndex, opSlice, length for joiner?

Jonathan M Davis via Digitalmars-d digitalmars-d at puremagic.com
Fri Jan 22 03:23:05 PST 2016


On Friday, 22 January 2016 at 10:18:20 UTC, Maverick Chardet 
wrote:
> On Friday, 22 January 2016 at 01:02:10 UTC, Andrei Alexandrescu 
> wrote:
>> On 01/21/2016 05:22 PM, Maverick Chardet wrote:
>>> Just a question: is it possible for a range to be considered 
>>> infinite
>>> and at the same time have a length? I suppose that if it is 
>>> possible,
>>> such a range would be ill-formed...
>>
>> Indeed that range would be ill-formed. -- Andrei
>
> Okay so I'll just use an assert!
>
>
> Something is bothering me though, I'm wondering why walkLength 
> does not save the range when possible (when it is an input 
> range)? For now it's just making a copy, couldn't it be 
> problematic in some cases? The current code is:
>
>
> auto walkLength(Range)(Range range)
>     if (isInputRange!Range && !isInfinite!Range)
> {
>     static if (hasLength!Range)
>         return range.length;
>     else
>     {
>         size_t result;
>         for ( ; !range.empty ; range.popFront() )
>             ++result;
>         return result;
>     }
> }
>
>
> Why not something like this:
>
>
> auto walkLength(Range)(const ref Range range)
>     if (isInputRange!Range && !isInfinite!Range)
> {
>     static if (hasLength!Range)
>         return range.length;
>     else
>     {
>         size_t result;
>         static if (isForwardRange!range)
>         {
>             Range rangeCopy = range.save;
>         }
>         else
>         {
>             Range rangeCopy = range;
>         }
>         for ( ; !rangeCopy.empty ; rangeCopy.popFront() )
>             ++result;
>         return result;
>     }
> }

Arguably, walkLength shouldn't even accept a range that isn't a 
forward range, since if it's not, then walkLength is just going 
to eat the range. As for calling save, there's no point. It's too 
late as soon as you've passed the range into the function, since 
that copied the range, which is undefined behavior due to the 
fact that the exact semantics of copying a range vary wildly 
depending on how a range is implemented. In generic code, if you 
want to use a range after passing it to a function, you have to 
call save and pass that to the function; otherwise, you get 
undefined behavior when you do anything with the range after 
passing it to the function.

Also, I would point out that passing by const ref isn't going to 
work. The range would be const, so you couldn't iterate over it 
(and save returns the exact same type as the range, so it 
wouldn't remove const even if it could - at it probably can't 
anyway). And if the function takes the range by ref, then it will 
consume it, which you really don't want. Calling save would get 
around that problem, but then you'd still have the problem that 
the function wouldn't accept rvalues, which would be highly 
annoying.

- Jonathan M Davis


More information about the Digitalmars-d mailing list