Thread overview | |||||||
---|---|---|---|---|---|---|---|
|
April 29, 2020 Can’t use UFCS to create InputRange? | ||||
---|---|---|---|---|
| ||||
struct R {}
int front(R r) { return 42; }
void popFront(R r) {}
bool empty(R r) { return false; }
void main() {
import std.range.primitives : isInputRange;
static assert(isInputRange!R);
}
> Error: static assert: `isInputRange!(R)` is false
Whats really weird is that if I replace isInputRange with its definition from std.range.primitives, it returns true:
import std;
struct R {}
int front(R r) { return 42; }
void popFront(R r) {}
bool empty(R r) { return false; }
void main() {
static assert(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)));
}
This compiles.
What’s going on here?
|
April 29, 2020 Re: Can’t use UFCS to create InputRange? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ogi | On Wednesday, 29 April 2020 at 08:34:53 UTC, Ogi wrote:
> struct R {}
> int front(R r) { return 42; }
> void popFront(R r) {}
> bool empty(R r) { return false; }
>
> void main() {
> import std.range.primitives : isInputRange;
> static assert(isInputRange!R);
> }
>
>> Error: static assert: `isInputRange!(R)` is false
>
> What’s going on here?
The template IsInputRange is in the std.range.primitives module, and thus can't see the front, popFront and empty definitions in your module.
--
Simen
|
April 29, 2020 Re: Can’t use UFCS to create InputRange? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ogi | On Wednesday, 29 April 2020 at 08:34:53 UTC, Ogi wrote:
> struct R {}
> int front(R r) { return 42; }
> void popFront(R r) {}
> bool empty(R r) { return false; }
>
> void main() {
> import std.range.primitives : isInputRange;
> static assert(isInputRange!R);
> }
>
>> Error: static assert: `isInputRange!(R)` is false
>
> Whats really weird is that if I replace isInputRange with its definition from std.range.primitives, it returns true:
>
> import std;
>
> struct R {}
> int front(R r) { return 42; }
> void popFront(R r) {}
> bool empty(R r) { return false; }
>
> void main() {
> static assert(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)));
> }
> This compiles.
>
> What’s going on here?
The static checker doesn't see your free funcs because to do so it would have to import the whole module. (is it possible to do that ? no idea.)
Also your signature for the primitives are quite unusual (i.e not idiomatic). Usually they dont take param. Usually we pass a type that contains the member funcs matching to IsIntputRange.
|
April 29, 2020 Re: Can’t use UFCS to create InputRange? | ||||
---|---|---|---|---|
| ||||
Posted in reply to user1234 | On Wednesday, 29 April 2020 at 09:16:58 UTC, user1234 wrote: > The static checker doesn't see your free funcs because to do so it would have to import the whole module. (is it possible to do that ? no idea.) Of course it's possible! :) We can find the context of R (in this case, the module) with __traits(parent), and import that: mixin("import "~__traits(parent, R).stringof["module ".length..$]~";"); However, doing that in isInputRange doesn't help much. First, all other range functions would have to do it, and second, just importing into function scope doesn't enable UFCS lookup. > Also your signature for the primitives are quite unusual (i.e not idiomatic). Usually they dont take param. Usually we pass a type that contains the member funcs matching to IsIntputRange. You can see a good counterexample to this in https://dlang.org/library/std/range/primitives/pop_front.html, which defines popFront for regular arrays. However, that is the one and only counterexample I know of. Of course, nothing stops us from defining our own front, popFront and friends that combine the two approaches above: template front(R) { auto front(R r) { return __traits(getMember, __traits(parent, R), "front")(r); } } template popFront(R) { auto popFront(R r) { return __traits(getMember, __traits(parent, R), "popFront")(r); } } template empty(R) { auto empty(R r) { return __traits(getMember, __traits(parent, R), "empty")(r); } } We could conceivably add these to std.range.primitives (probably adding some constraints first), and suddenly UFCS ranges are possible! (I am as of yet not convinced that we should, though) -- Simen |
April 29, 2020 Re: Can’t use UFCS to create InputRange? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simen Kjærås | On Wednesday, 29 April 2020 at 12:23:11 UTC, Simen Kjærås wrote: > Of course, nothing stops us from defining our own front, popFront and friends that combine the two approaches above: > [...] > > We could conceivably add these to std.range.primitives (probably adding some constraints first), and suddenly UFCS ranges are possible! (I am as of yet not convinced that we should, though) > > -- > Simen This is basically what C++ calls "argument-dependent lookup." Discussion about adding this sort of thing to D has come up before on the forums [1], and iirc Walter has generally been opposed to it. If it were to be added as a library feature, it would probably have to be opt-in. [1] https://forum.dlang.org/post/mailman.123.1472818535.2965.digitalmars-d@puremagic.com |
Copyright © 1999-2021 by the D Language Foundation