How can I test at compile time whether T is an instance of an interface ?

data pulverizer data.pulverizer at gmail.com
Wed Sep 23 20:19:04 UTC 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.
>
>
> T

This 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
```



More information about the Digitalmars-d-learn mailing list