range.save

Jonathan M Davis via Digitalmars-d digitalmars-d at puremagic.com
Fri Nov 27 02:43:26 PST 2015


On Friday, 27 November 2015 at 10:17:46 UTC, Joseph Rushton 
Wakeling wrote:
> On Friday, 27 November 2015 at 09:20:23 UTC, Jonathan M Davis 
> wrote:
>> Obviously, Andrei will have to answer to know what he meant, 
>> but with regards to ranges, I would consider a reference type 
>> to be one where in
>>
>> auto copy = range;
>>
>> doing anything to copy or range does the exact same thing to 
>> the other, because they refer to the exact same state. 
>> Something like save is required to get a separate range where 
>> popping elements from one will not affect the other.
>
> Unfortunately it's a bit more complicated than that, because 
> it's readily possible to have ranges where
>
>     auto copy = range;
>
> ... will copy _some_ of the internals by value, and some by 
> reference -- e.g. a range whose private data includes some 
> integer values and a dynamic array.
>
> That's not necessarily a problem if the reference-type data 
> does not influence the range's behaviour (e.g. you're doing 
> forward iteration over a container accessed by ref), but it's 
> readily possible to imagine a range design where
>
>     auto copy = range;
>     copy.popFront();
>
> ... will affect range's state without updating it to the _same_ 
> state as copy.

Yes. I discussed that in my post, though maybe I wasn't clear 
enough. But such a range requires save just as much as a full-on 
reference type does, so ultimately it's pretty much in the same 
boat as far as save goes. It's also a serious problem for pure 
input ranges to such ranges exist, since then even if you can 
assume that any range which can implement save does implement 
save, you still can't guarantee that an input range is a 
reference type, which becomes a serious problem when an input 
range is copied. e.g.

foreach(e; range)
{
     if(cond)
         break;
}
range.popFront();

could be fine if you can guarantee that the range is a reference 
type, but if you can't guarantee that (as is currently the case), 
then as soon as you use a pure input range with a foreach loop, 
you can't use it anymore, because it's copied as part of the 
lowering. To get around that, you can use a for loop directly, 
but the fact that pure input ranges aren't currently guaranteed 
to be reference types definitely makes it harder to write 
consistent, correct code with pure input ranges.

As it stands, forward ranges have the same problem, but by 
calling save, you can ensure that the copy is separate from the 
original and ensure that iterating the original after the loop is 
fine (though if you want reference semantics, you would still 
have to use a for loop), but pure input ranges don't have a way 
to ensure consistency like that other than maybe wrapping the 
range in another type which you can guarantee is a reference type.

Regardless, even if we require that pure input ranges be 
reference types and that forward ranges be value types (at least 
insomuch as copying them results in a separate range with the 
same state like with save), we then still have the problem that 
pure input ranges and forward ranges have different semantics. 
But as long as dynamic arrays are ranges, it's not like we could 
force all ranges to be reference types, and that wouldn't be good 
for efficiency anyway, since it would almost certainly mean more 
heap allocations just so that they can be reference types.

- Jonathan M Davis


More information about the Digitalmars-d mailing list