foreach() behavior on ranges

Steven Schveighoffer schveiguy at gmail.com
Wed Aug 25 17:01:54 UTC 2021


On 8/25/21 12:46 PM, Joseph Rushton Wakeling wrote:
> On Wednesday, 25 August 2021 at 10:59:44 UTC, Steven Schveighoffer wrote:
>> structs still provide a mechanism (postblit/copy ctor) to properly 
>> save a forward range when copying, even if the guts need copying 
>> (unlike classes). In general, I think it was a mistake to use `.save` 
>> as the mechanism, as generally `.save` is equivalent to copying, so 
>> nobody does it, and code works fine for most ranges.
> 
> Consider a struct whose internal fields are just a pointer to its "true" 
> internal state.  Does one have any right to assume that the 
> postblit/copy ctor would necessarily deep-copy that?

In a world where copyability means it's a forward range? Yes. We aren't 
in that world, it's a hypothetical "if we could go back and redesign".

> If that struct implements a forward range, though, and that pointed-to 
> state is mutated by iteration of the range, then it would be reasonable 
> to assume that the `save` method MUST deep-copy it, because otherwise 
> the forward-range property would not be respected.
> 
> With that in mind, I am not sure it's reasonable to assume that just 
> because a struct implements a forward-range API, that copying the struct 
> instance is necessarily the same as saving the range.

Technically this is true. In practice, it rarely happens. The flaw of 
`save` isn't that it's an unsound API, the flaw is that people get away 
with just copying, and it works 99.9% of the time. So code is simply 
untested with ranges where `save` is important.

> Indeed, IIRC quite a few Phobos library functions program defensively 
> against that difference by taking a `.save` copy of their input before 
> iterating over it.

I'd be willing to bet $10 there is a function in phobos right now, that 
takes forward ranges, and forgets to call `save` when iterating with 
foreach. It's just so easy to do, and works with most ranges in existence.

> 
>> What should have happened is that input-only ranges should not have 
>> been copyable, and copying should have been the save mechanism. Then 
>> it becomes way way more obvious what is happening. Yes, this means 
>> forgoing classes as ranges.
> 
> I think there's a benefit of a method whose definition is explicitly "If 
> you call this, you will get a copy of the range which will replay 
> exactly the same results when iterating over it".  Just because the 
> meaning of "copy" can be ambiguous, whereas a promise about how 
> iteration can be used is not.

The idea is to make the meaning of a range copy not ambiguous.

-Steve


More information about the Digitalmars-d-learn mailing list