called copy constructor in foreach with ref on Range
Stanislav Blinov
stanislav.blinov at gmail.com
Tue Jun 23 01:31:37 UTC 2020
On Monday, 22 June 2020 at 21:33:08 UTC, H. S. Teoh wrote:
> Don't be shocked when you find out how many Phobos ranges have
> .init states that are invalid (e.g., non-empty, but .front and
> .popFront will crash / return invalid values).
Which ones?
> Jonathan is coming from the POV of generic code. The problem
> with move leaving the original range in its .init state isn't
> so much that it will crash or anything (even though as you said
> that does indicate a flaw in the range's implementation), but
> that the semantics of generic code changes in subtle ways.
Well that means that the code is not generic, i.e. the bug
originates in the design, not implementation.
> auto myGenericFunc(R)(R r) {
> ...
> foreach (x; r) {
> doSomething(x);
> }
> if (!r.empty)
> doSomethingElse(r);
> ...
> }
>
> Suppose for argument's sake that the above foreach/if structure
> is an essential part of whatever algorithm myGenericFunc is
> implementing. Now there's a problem, because if R has
> array-like semantics, then the algorithm will do one thing, but
> if R has reference-like or move semantics, then the behaviour
> of the algorithm will be different, even if both ranges
> represent the same sequence of input values.
Yep, definitely not generic. Which is exactly the kind of error
that should be caught at compile time. Which we, sadly, can't do
with the current range API.
> consider a function that drops the first n elements of a range.
> Your generic function might want to pop the first n elements
> then do something else with the rest of the range. Well, if
> you write it the obvious way:
>
> auto myAlgo(R)(R r) {
> size_t n = ...;
> dropFirstN(r, n);
> ... // do something else with r
> }
>
> then you have a subtle bug, because the state of r after the
> call to dropFirstN might be completely different depending on
> whether r behaves like an array or like a by-reference or move
> type.
Err... that one is actually fine. It would take the range by ref
and pop off the elements. There already is such a function - the
popFrontN. It's the functions that take ranges by value that
present the not-so-subtle issue with reference types. For
example, its chainable would-be-counterpart drop(). "Would-be"
because that one takes the argument by value.
We should move toward disallowing reference types to be ranges. A
good deal of the rest can be solved with API and design changes
(like disallowing copying of input ranges).
It's kind of interesting how, with the ongoing discussion about
range API in the general forum, a couple of range questions are
brought up in learn. Something, as they say, is in the air.
More information about the Digitalmars-d-learn
mailing list