To be consistent with the old definition of forward ranges, and with arrays and opApply-based ranges, a foreach loop should call save() if it's available. The example below demonstrates why not doing so is problematic.
import std.stdio;
class SomeRange {
uint num;
uint front() {
return num;
}
void popFront() {
num++;
}
bool empty() @property {
return num >= 10;
}
typeof(this) save() @property {
auto ret = new typeof(this);
ret.num = num;
return ret;
}
}
void main() {
auto r = new SomeRange;
foreach(elem; r) {
writeln(elem); // Prints numbers 0-9.
}
foreach(elem; r) {
writeln(elem); // Nothing.
}
}
Comment #1 by torarind — 2011-05-05T18:47:16Z
I think save() should be required, since the semantics of foreach when iterating over arrays imply a save() on the array. Letting forward range behaviour depend on whether the range is a class or a struct is bound to be confusing.
Comment #2 by monarchdodra — 2014-06-12T20:02:18Z
I disagree with this. saving a range should always be the caller's responsibility/choice.
If the argument "people expect the range to be saved" prevails here, it means "save" is failed as a concept, and forward ranges should simply be defined as "ranges that implicitly save on copy": EG no need for save, only for a postblit that's *always* called.
Comment #3 by andrei — 2016-12-22T14:35:53Z
I'll close this because addressing it may disrupt code. Also it would make behavior of foreach different across input and other ranges.
Comment #4 by mathias.lang — 2016-12-22T14:56:45Z
@Andrei: Actually, there is already a difference in behavior. When iterating over a range which is a reference (e.g. class), the range will be advanced by foreach.
However, for value types (structs), the struct is copied, resulting in an implict `.save` most of the time.
See https://issues.dlang.org/show_bug.cgi?id=15413 for example.
Comment #5 by andrei — 2016-12-22T15:05:01Z
(In reply to Mathias Lang from comment #4)
> @Andrei: Actually, there is already a difference in behavior. When iterating
> over a range which is a reference (e.g. class), the range will be advanced
> by foreach.
> However, for value types (structs), the struct is copied, resulting in an
> implict `.save` most of the time.
> See https://issues.dlang.org/show_bug.cgi?id=15413 for example.
I understand that. Still think we should not change behavior.