Thread overview
isInputRange copied verbatim produces a different result than isInputRange from std.range
Mar 04, 2018
aliak
Mar 04, 2018
Adam D. Ruppe
Mar 04, 2018
aliak
Mar 04, 2018
aliak
Mar 04, 2018
ag0aep6g
Mar 04, 2018
arturg
Mar 04, 2018
Jonathan M Davis
Mar 04, 2018
arturg
March 04, 2018
Hi, I have a custom type D with front/popFront/empty implemented as free functions, but isInputRange returns false. I copied the implementation of isInputRange, and that custom implementation returns true... anyone know what's going on here?

===
import std.stdio, std.range, std.traits;

// Code copied veratim from:
// https://github.com/dlang/phobos/blob/v2.079.0/std/range/primitives.d#L164
enum bool isIR(R) =
    is(typeof(R.init) == R)
    && is(ReturnType!((R r) => r.empty) == bool)
    && is(typeof((return ref R r) => r.front))
    && !is(ReturnType!((R r) => r.front) == void)
    && is(typeof((R r) => r.popFront));

struct D {}

@property int front(D d) { return 2; }
@property bool empty(D d) { return false; }
void popFront(D d) {}

pragma(msg, isIR!D); // true
pragma(msg, isInputRange!D); // false ???

pragma(msg, is(typeof(D.init) == D)); // true
pragma(msg, is(ReturnType!((D r) => r.empty) == bool)); // true
pragma(msg, is(typeof((return ref D r) => r.front))); // true
pragma(msg, !is(ReturnType!((D r) => r.front) == void)); // true
pragma(msg, is(typeof((D r) => r.popFront))); // true

void main() {}
===

Thanks for any help!
- Ali
March 04, 2018
On Sunday, 4 March 2018 at 12:57:41 UTC, aliak wrote:
> @property int front(D d) { return 2; }
> @property bool empty(D d) { return false; }
> void popFront(D d) {}

Those functions are in scope for your function, but not inside std.range.

in other words std.range hasn't imported your module, so it can't see those three functions.
March 04, 2018
On Sunday, 4 March 2018 at 13:17:30 UTC, Adam D. Ruppe wrote:
> On Sunday, 4 March 2018 at 12:57:41 UTC, aliak wrote:
>> @property int front(D d) { return 2; }
>> @property bool empty(D d) { return false; }
>> void popFront(D d) {}
>
> Those functions are in scope for your function, but not inside std.range.
>
> in other words std.range hasn't imported your module, so it can't see those three functions.

Ah, of course!
Thanks!
March 04, 2018
On Sunday, 4 March 2018 at 13:17:30 UTC, Adam D. Ruppe wrote:
> On Sunday, 4 March 2018 at 12:57:41 UTC, aliak wrote:
>> @property int front(D d) { return 2; }
>> @property bool empty(D d) { return false; }
>> void popFront(D d) {}
>
> Those functions are in scope for your function, but not inside std.range.
>
> in other words std.range hasn't imported your module, so it can't see those three functions.

wait a minute... so I can't use any std.range functions on a type if I add the range primitives as free functions? O.o
March 04, 2018
On 03/04/2018 08:54 PM, aliak wrote:
> wait a minute... so I can't use any std.range functions on a type if I add the range primitives as free functions? O.o

Yes. In other words: You can't implement range primitives as free functions. Because std.range (and std.algorithm, etc.) doesn't know about them.
March 04, 2018
On Sunday, 4 March 2018 at 19:58:14 UTC, ag0aep6g wrote:
> On 03/04/2018 08:54 PM, aliak wrote:
>> wait a minute... so I can't use any std.range functions on a type if I add the range primitives as free functions? O.o
>
> Yes. In other words: You can't implement range primitives as free functions. Because std.range (and std.algorithm, etc.) doesn't know about them.

isn't this what DIP 1005 tried to solve?

as long as you dont want to role your own test its not possible.

module moda;

struct Imports
{
    string importString;
}

template isInputRange(R)
{
    import std.traits: hasUDA, getUDAs, ReturnType;

    static if(hasUDA!(R, Imports))
    static foreach(u; getUDAs!(R, Imports))
    mixin(u.importString);

    enum bool isInputRange =
        is(typeof(R.init) == R)
        && is(ReturnType!((R r) => r.empty) == bool)
        && is(typeof((return ref R r) => r.front))
        && !is(ReturnType!((R r) => r.front) == void)
        && is(typeof((R r) => r.popFront));
}

-----

module test;

import std.stdio;
import moda;

void main(string[] args)
{
    isInputRange!Type.writeln;
}

bool empty(Type t) { return true; }
int front(Type t) { return 42; }
void popFront(Type t) {}

@Imports("import test: empty, front, popFront;")
struct Type
{
}


March 04, 2018
On Sunday, March 04, 2018 21:03:23 arturg via Digitalmars-d-learn wrote:
> On Sunday, 4 March 2018 at 19:58:14 UTC, ag0aep6g wrote:
> > On 03/04/2018 08:54 PM, aliak wrote:
> >> wait a minute... so I can't use any std.range functions on a type if I add the range primitives as free functions? O.o
> >
> > Yes. In other words: You can't implement range primitives as free functions. Because std.range (and std.algorithm, etc.) doesn't know about them.
>
> isn't this what DIP 1005 tried to solve?

No. What DIP 1005 was trying to solve was avoiding having to have imports used by your function signature or template constraint on top-level constructs be available to the entire module. It wanted the imports to only kick in when the symbol that needed them was used. So, it would be possible to then import isInputRange as part of a function that needed it in its template constraint without the rest of the module seeing that import, whereas right now, such an import would have to be at the top level and would affect the entire module. DIP 1005 didn't do anything to make it so that other modules could see what you imported, and I doubt that any DIP ever would, because if that were possible, it would cause function hijacking, because you could force other modules to import what you wanted instead of what the person who wrote them imported.

- Jonathan M Davis

March 04, 2018
On Sunday, 4 March 2018 at 21:47:43 UTC, Jonathan M Davis wrote:
> On Sunday, March 04, 2018 21:03:23 arturg via Digitalmars-d-learn wrote:
>>
>> isn't this what DIP 1005 tried to solve?
>
> No. What DIP 1005 was trying to solve was avoiding having to have imports used by your function signature or template constraint on top-level constructs be available to the entire module. It wanted the imports to only kick in when the symbol that needed them was used. So, it would be possible to then import isInputRange as part of a function that needed it in its template constraint without the rest of the module seeing that import, whereas right now, such an import would have to be at the top level and would affect the entire module. DIP 1005 didn't do anything to make it so that other modules could see what you imported, and I doubt that any DIP ever would, because if that were possible, it would cause function hijacking, because you could force other modules to import what you wanted instead of what the person who wrote them imported.
>
> - Jonathan M Davis

hm yeah i hoped that dip 1005 would be introspectable so you could use it instead of relying on udas.