On Sunday, February 16, 2020 3:41:31 AM MST uranuz via Digitalmars-d-learn wrote: > I have reread presentation: > http://dconf.org/2015/talks/davis.pdf > We declare that `pure` input range cannot be `unpoped` and we > can't return to the previous position of it later at the time. So > logically there is no sence of copying input range at all. So > every Phobos algorithm that declares that it's is working with > InputRange must be tested for working with range with disabled > copy constructor and postblit. And if it is not it means that > this algroithm actually requires a forward range and there we > missing `save` calls? > Because as it was written in this presentation a range copy is > undefined (without call to save). So it's illegal to create copy > of range in Phobos algorithms without `save`? > So we need a test for every algorithm that it is working with > range with disabled copy constructor and postblit if we declare > that we only use `save` for range copy?
A range that can't be copied is basically useless. Not only do almost all range-based algorithms take their argumenst by value (and thus copy them), but foreach copies any range that it's given, meaning that if a range isn't copyable, you can't even use it with foreach. And since many range-based algorithms function by wrapping one range with another, the ability to copy ranges is fundamental to most range-based code. That being said, the semantics of copying a range are not actually defined by the range API. Whether iterating over a copy affects the original depends on how a range was implemented. e.g. In code such as void foo(R)(R r) if(isInputRange!R) { r.popFront(); } foo(range); whether the range in the original range in the calling code is affected by the element being popped from the copy inside of foo is implementation dependent. If it's a class or a struct that's a full-on reference type, then mutating the copy does affect the original, whereas if copying a range is equivalent to save, then mutating the copy has no effect on the original. And with pseudo-reference types, it's even worse, because you could end up _partially_ mutating the original by mutating the copy, meaning that you can get some pretty serious bugs if you attempt to use a range after it's been copied. This means that in practice, in generic code, you can never use a range once it's been copied unless you overwrite it with a new value. Passing a range to a function or using it with foreach basically means that you should not continue to use that range, and if you want to be able to continue to use it, you need to call save and pass that copy to the function or foreach instead of passing the range directly to a function or foreach. In order to fix it so that you can rely on the semantics of using a range after it's been copied, we'd have to rework the range API and make it so that the semantics of copying a range were well-defined, and that gets into a huge discussion on its own. As things stand, if you want to test range-based code to ensure that it works correctly (including calling save correctly), you have to test it with a variety of different range types, including both ranges where copying is equivalent to calling save and ranges which are reference types so that copying them simply results in another reference to the same data such that iterating one copy iterates all copies. - Jonathan M Davis