foreach() behavior on ranges

Joseph Rushton Wakeling joseph.wakeling at webdrake.net
Wed Aug 25 16:46:54 UTC 2021


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?

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.

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.

> 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.


More information about the Digitalmars-d-learn mailing list