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