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.

Reply via email to