digitalmars.D.learn - How can I test at compile time whether T is an instance of an
- wjoe (21/21) Sep 23 2020 I have some similar functions:
- data pulverizer (5/26) Sep 23 2020 A class at compile time is it's own static type, OOP polymorphism
- wjoe (7/13) Sep 23 2020 It doesn't occur to me that the compiler doesn't know at compile
- data pulverizer (4/9) Sep 23 2020 Didn't think that the compiler didn't know but wasn't aware that
- H. S. Teoh (11/24) Sep 23 2020 Of course the compiler knows. And of course it can use this information
- data pulverizer (67/76) Sep 23 2020 This has prompted me to write a data structure that I thought
- data pulverizer (18/20) Sep 23 2020 Here is the function with the correct template constraint:
- data pulverizer (11/13) Sep 23 2020 False alarm:
- data pulverizer (20/25) Sep 24 2020 On Wednesday, 23 September 2020 at 20:19:04 UTC, data pulverizer
- wjoe (4/9) Sep 23 2020 Appologies if you took offense. Your replies are very much
- data pulverizer (2/4) Sep 23 2020 No offense taken.
- H. S. Teoh (15/15) Sep 23 2020 Try this:
- wjoe (2/15) Sep 23 2020 Yes, that's it. Thanks :)
- =?UTF-8?B?T3TDoXZpbw==?= Augusto (2/23) Sep 23 2020 see if "import std.traits: isImplicitlyConvertible" helps you.
I have some similar functions: void register(C: IFoo)() { _insert!C(); } void register(C)() if (behavesLikeFoo!C) { _insert!C(); } There are more overloads with parameters so I want to merge them void register(C, ARGS...)(ARGS args) if (behavesLikeFoo!C || isInstanceOf!(C, IFoo)) { _insert!C(args); } I found a lot of information on how to do this at runtime but not at compile time. std.traits: isInstanceOf doesn't work. Neither did anything I tried with typeid etc. The behavesLikeFoo constraint works as expected but it accepts any class no matter whether or not it implements the interface.
Sep 23 2020
On Wednesday, 23 September 2020 at 18:37:45 UTC, wjoe wrote:I have some similar functions: void register(C: IFoo)() { _insert!C(); } void register(C)() if (behavesLikeFoo!C) { _insert!C(); } There are more overloads with parameters so I want to merge them void register(C, ARGS...)(ARGS args) if (behavesLikeFoo!C || isInstanceOf!(C, IFoo)) { _insert!C(args); } I found a lot of information on how to do this at runtime but not at compile time. std.traits: isInstanceOf doesn't work. Neither did anything I tried with typeid etc. The behavesLikeFoo constraint works as expected but it accepts any class no matter whether or not it implements the interface.A class at compile time is it's own static type, OOP polymorphism is a runtime feature not compile time. You have to write your own traits for specific objects to get them to relate to each other using static overloading.
Sep 23 2020
On Wednesday, 23 September 2020 at 18:49:28 UTC, data pulverizer wrote:On Wednesday, 23 September 2020 at 18:37:45 UTC, wjoe wrote:It doesn't occur to me that the compiler doesn't know at compile time that interface IFoo{} class Foo: IFoo {} class Foo implements interface IFoo.[...]A class at compile time is it's own static type, OOP polymorphism is a runtime feature not compile time. You have to write your own traits for specific objects to get them to relate to each other using static overloading.
Sep 23 2020
On Wednesday, 23 September 2020 at 18:56:33 UTC, wjoe wrote:It doesn't occur to me that the compiler doesn't know at compile time that interface IFoo{} class Foo: IFoo {} class Foo implements interface IFoo.Didn't think that the compiler didn't know but wasn't aware that you could use that information to statically dispatch. My mistake, I'll shut up now!
Sep 23 2020
On Wed, Sep 23, 2020 at 07:08:47PM +0000, data pulverizer via Digitalmars-d-learn wrote:On Wednesday, 23 September 2020 at 18:56:33 UTC, wjoe wrote:Of course the compiler knows. And of course it can use this information for static dispatch. That's why D is so awesome at metaprogramming. ;-) What the compiler *doesn't* know is whether a variable of some supertype of Foo (say Object) implements IFoo, because that's something that can only be determined at runtime (effectively, you need to downcast to Foo / IFoo and test if it's null). But that's not what the OP is asking for in this case. T -- Error: Keyboard not attached. Press F1 to continue. -- Yoon Ha Lee, CONLANGIt doesn't occur to me that the compiler doesn't know at compile time that interface IFoo{} class Foo: IFoo {} class Foo implements interface IFoo.Didn't think that the compiler didn't know but wasn't aware that you could use that information to statically dispatch. My mistake, I'll shut up now!
Sep 23 2020
On Wednesday, 23 September 2020 at 19:16:13 UTC, H. S. Teoh wrote:Of course the compiler knows. And of course it can use this information for static dispatch. That's why D is so awesome at metaprogramming. ;-) What the compiler *doesn't* know is whether a variable of some supertype of Foo (say Object) implements IFoo, because that's something that can only be determined at runtime (effectively, you need to downcast to Foo / IFoo and test if it's null). But that's not what the OP is asking for in this case. TThis has prompted me to write a data structure that I thought would be impossible until now. It's a data structure with a Start node with a link to next, then any number of Middle nodes with previous and next links, and an End node with a previous link all inheriting from a common interface Node. This is of course possible using runtime polymorphism, but I wanted it available for static dispatch rather than everything being listed as "Node" static type. The implementation is below and works. Interestingly when I wrote it down with a pen and paper I thought that it would lead to infinitely recursive unwriteable data type and so didn't even bother trying to implement it. But D actually forms the correct static type, it prints the gobbledygook type I expect at compile time but the actual static type at runtime. Amazing! I have been using structs with tuples because I thought this data structure was impossible! ``` import std.stdio: writeln; interface Node{} class Start: Node { Node next; } class Middle: Node { Node prev; Node next; } class End: Node { Node prev; } auto makeChain(Args...)(Args args) if(Args.length > 3) { args[0].next = args[1]; static foreach(i; 1..(Args.length - 1)) { args[i].prev = args[i - 1]; args[i].next = args[i + 1]; } args[$ - 1].prev = args[$ - 2]; return args[0]; } void main() { static const x = makeChain(new Start(), new Middle(), new Middle(), new Middle(), new Middle(), new End()); pragma(msg, "x.next: ", x.next, "\n"); writeln("x.next: ", x.next); } ``` output: ``` x.next: Middle(Start(Middle(<recursion>)), Middle(Middle(Start(Middle(<recursion>)), Middle(<recursion>)), Middle(Middle(Middle(Start(Middle(<recursion>)), Middle(<recursion>)), Middle(<recursion>)), Middle(Middle(Middle(Middle(Start(Middle(<recursion>)), Middle(<recursion>)), Middle(<recursion>)), Middle(<recursion>)), End(Middle(Middle(Middle(Middle(Start(Middle(<recursion>)), Middle(<recursion>)), Middle(<recursion>)), Middle(<recursion>)), End(<recursion>))))))) x.next: node.Middle ```
Sep 23 2020
On Wednesday, 23 September 2020 at 20:19:04 UTC, data pulverizer wrote:This has prompted me to write a data structure that I thought would be impossible until now. [...SNIP...]Here is the function with the correct template constraint: ``` auto makeChain(Args...)(Args args) if(Args.length > 2 && is(Args[0] == Start) && is(Args[Args.length - 1] == End)) { args[0].next = args[1]; static foreach(i; 1..(Args.length - 1)) { args[i].prev = args[i - 1]; args[i].next = args[i + 1]; } args[$ - 1].prev = args[$ - 2]; return args[0]; } ```
Sep 23 2020
On Wednesday, 23 September 2020 at 20:19:04 UTC, data pulverizer wrote:This has prompted me to write a data structure that I thought would be impossible until now....False alarm: ``` writeln("typeof(x.next): ", typeof(x.next).stringof); ``` gives: ``` typeof(x.next): const(Node) ``` Oh well.
Sep 23 2020
On Wednesday, 23 September 2020 at 20:19:04 UTC, data pulverizer wrote: Thinking more about it this ...class Middle: Node { Node prev; Node next; }won't work because the I've told the compiler that the static type is "Node", my original design was something like this: ``` struct Middle(P, N) { P prev; N next; } ``` which also won't work because it can't actually be instantiated (recursive), and the start and end nodes must be different types (and you can't substitute the middle node for the start and end node). It's the simplest case because there could be more than one type of middle node. More generally, correct me if I'm wrong, but I don't think these kinds of statically multityped tree structures can be formed in static languages so I've been using tuples - at least for the simple case I outlined.
Sep 24 2020
On Wednesday, 23 September 2020 at 19:08:47 UTC, data pulverizer wrote:On Wednesday, 23 September 2020 at 18:56:33 UTC, wjoe wrote:Appologies if you took offense. Your replies are very much appreciated.[...]Didn't think that the compiler didn't know but wasn't aware that you could use that information to statically dispatch. My mistake, I'll shut up now!
Sep 23 2020
On Wednesday, 23 September 2020 at 19:27:13 UTC, wjoe wrote:Appologies if you took offense. Your replies are very much appreciated.No offense taken.
Sep 23 2020
Try this: interface I {} class C : I {} class D {} struct S {} pragma(msg, is(C : I)); // true pragma(msg, is(D : I)); // false pragma(msg, is(S : I)); // false So probably what you want is something like this: void register(C, ARGS...)(ARGS args) if (behavesLikeFoo!C || is(C : IFoo)) ... T -- Change is inevitable, except from a vending machine.
Sep 23 2020
On Wednesday, 23 September 2020 at 18:50:28 UTC, H. S. Teoh wrote:Try this: interface I {} class C : I {} class D {} struct S {} pragma(msg, is(C : I)); // true pragma(msg, is(D : I)); // false pragma(msg, is(S : I)); // false So probably what you want is something like this: void register(C, ARGS...)(ARGS args) if (behavesLikeFoo!C || is(C : IFoo)) ... TYes, that's it. Thanks :)
Sep 23 2020
On Wednesday, 23 September 2020 at 18:37:45 UTC, wjoe wrote:I have some similar functions: void register(C: IFoo)() { _insert!C(); } void register(C)() if (behavesLikeFoo!C) { _insert!C(); } There are more overloads with parameters so I want to merge them void register(C, ARGS...)(ARGS args) if (behavesLikeFoo!C || isInstanceOf!(C, IFoo)) { _insert!C(args); } I found a lot of information on how to do this at runtime but not at compile time. std.traits: isInstanceOf doesn't work. Neither did anything I tried with typeid etc. The behavesLikeFoo constraint works as expected but it accepts any class no matter whether or not it implements the interface.see if "import std.traits: isImplicitlyConvertible" helps you.
Sep 23 2020