foreach() behavior on ranges
Alexandru Ermicioi
alexandru.ermicioi at gmail.com
Tue Aug 24 19:06:44 UTC 2021
On Tuesday, 24 August 2021 at 09:15:23 UTC, bauss wrote:
>
> A range should be a struct always and thus its state is copied
> when the foreach loop is created.
Actually the range contracts don't mention that it needs to be a
by value type. It can also be a reference type, i.e. a class.
>
> Which means the state resets every time the loop is initiated.
True for any forward range and above, not true for input ranges.
The problem with them is that some of them are structs, and even
if they are not forward ranges they do have this behavior due to
implicit copy on assignment, which can potentially make the code
confusing.
> If your range uses some internal state that isn't able to be
> copied then or your ranges are not structs then your ranges are
> inherently incorrect.
If we follow the definition of ranges, they must not be copy-able
at all. The only way to copy/save, would be to have .save method
and call that method. This again is not being properly followed
by even phobos implementations.
Note, that a better approach would be to replace .save in
definition of forward range with a copy constructor, then all
non-compliant ranges would become suddenly compliant, while those
that have .save method should be refactored to a copy constructor
version.
>
> This is what a foreach loop on a range actually compiles to:
>
> ```d
> for (auto copy = range; !copy.empty; copy.popFront())
> {
> ...
> }
> ```
You should add .save on assignment if range is a forward range,
or just remove the assignment if it is not.
Best regards,
Alexandru.
More information about the Digitalmars-d-learn
mailing list