Thread overview
Possible issue with isInputRange
Sep 23, 2015
Maor Ben Dayan
Sep 25, 2015
Alex Parrill
Sep 25, 2015
Lionello Lunesu
September 23, 2015
isInputRange will always return true for a range returning ref to non-copyable type.
This is a problem when trying to work with chain etc. together with such ranges.
The problem is that the test in isInputRange should have been similar to A below instead of B (no need to try and assign the return value of front for the range to be an input range).
Below is a reduced code example.

Am I correct in assuming that this is a phobos bug ?

code example:

void main()
{
    import std.range;
    import std.traits;

    struct Snowflake {
        int x;
        @disable this(this);
    }

    Snowflake[12] flakes;
    foreach(uint i; 0..flakes.length) {
        flakes[i].x = i;
    }
    alias R = Snowflake[];

    foreach(ref s; flakes[0..$]) { /* works just fine, I guess it is a valid input range */
        // do something
    }

    static assert(is(typeof((inout int = 0) { R r = R.init; })));
    static assert(is(typeof((inout int = 0) { R r = R.init; if (r.empty) {} })));
    static assert(is(typeof((inout int = 0) { R r = R.init; r.popFront(); })));
    static assert(is(typeof((inout int = 0) { R r = R.init; r.front; })));        /* A passes */
    static assert(is(typeof((inout int = 0) { R r = R.init; h = r.front; })));  /* B fails */
    static assert(isInputRange!(Snowflake[]));                                  /* fails */
}
September 25, 2015
On Wednesday, 23 September 2015 at 23:10:21 UTC, Maor Ben Dayan wrote:
> isInputRange will always return true for a range returning ref to non-copyable type.
> This is a problem when trying to work with chain etc. together with such ranges.
> The problem is that the test in isInputRange should have been similar to A below instead of B (no need to try and assign the return value of front for the range to be an input range).
> Below is a reduced code example.
>
> Am I correct in assuming that this is a phobos bug ?
>
> code example:
>
> void main()
> {
>     import std.range;
>     import std.traits;
>
>     struct Snowflake {
>         int x;
>         @disable this(this);
>     }
>
>     Snowflake[12] flakes;
>     foreach(uint i; 0..flakes.length) {
>         flakes[i].x = i;
>     }
>     alias R = Snowflake[];
>
>     foreach(ref s; flakes[0..$]) { /* works just fine, I guess it is a valid input range */
>         // do something
>     }
>
>     static assert(is(typeof((inout int = 0) { R r = R.init; })));
>     static assert(is(typeof((inout int = 0) { R r = R.init; if (r.empty) {} })));
>     static assert(is(typeof((inout int = 0) { R r = R.init; r.popFront(); })));
>     static assert(is(typeof((inout int = 0) { R r = R.init; r.front; })));        /* A passes */
>     static assert(is(typeof((inout int = 0) { R r = R.init; h = r.front; })));  /* B fails */
>     static assert(isInputRange!(Snowflake[]));
>               /* fails */
> }

It's because you disabled the copy constructor of `Snowflake`. Apparently `isInputRange` requires copyable elements (it does `auto h = r.front;` in its check).

Also, just because it's compatible with foreach loops doesn't mean it's a range; it may be an object with `opApply` (such as `std.parallelism.parallel` http://dlang.org/phobos/std_parallelism.html#.parallel)
September 25, 2015
On 24/09/15 07:10, Maor Ben Dayan wrote:
>      static assert(is(typeof((inout int = 0) { R r = R.init; h =
> r.front; })));  /* B fails */

What is `h`?