Some months ago I showed how inheritance and polymorphism work in compiled languages by reimplementing them with basic structs and function pointers. I wrote that code in D, but it could be translated directly to plain old C. In this post I’ll show how to take advantage of D’s features to make DIY inheritance a bit more ergonomic to use.
Although I have used these tricks in real code, I’m honestly just writing this because I think it’s neat what D can do, and because it helps explain how high-level features of D can be implemented — using the language itself.
In the original version of the code, the
Run command inherited from the
base class by including a
Command instance as its first member.
Command were still considered completely different types, so this meant explicit typecasting was
needed every time a
Run instance was polymorphically used as a
The D type system actually allows declaring a struct to be a subtype of another struct (or even of a primitive
type) using a feature called “
this”. Here’s a simple example of how it works:
The code above works in the same way as the code in the previous blog post, but
alias this tells
the type system what we’re doing. This allows us to work with the type system more, and do less
typecasting. The example showed a
Derived instance being passed by value as a
instance, but passing by
ref also works. Unfortunately, D version 2.081 won’t implicitly convert a
Derived* to a
Base*, but maybe it’ll be implemented in future.
Here’s an example of
alias this being used to implement some slightly more realistic
Unlike the code in the previous blog post, this version uses a vtable, just like the polymorphic inheritance
in normal compiled languages. As explained in the previous post, every
Penguin instance will use the
same list of function pointers for its virtual functions. So instead of repeating the function pointers in every
instance, we can have one list of function pointers that’s shared across all
(i.e., a list that’s a
static member). That’s all the vtable is, but it’s how real-world compiled
OOP languages work.
If we implemented another
Animal subtype, we’d have to add exactly the same vtable and base
member boilerplate as in
D has another feature for dumping this kind of boilerplate code into things: template mixins.
Actually, template mixins can take parameters, so it’s possible to create a generic
that inherits from any struct that defines a
VTable struct. Because template mixins can inject any
kind of declaration, including template functions, the
Derive mixin can even handle more complex
things, like the typecast from
Animal* to the subtype.
By the way, the
mixin statement can also be used
to “paste” code into places. It’s like a hygienic version of the C preprocessor, and it’s used below (and
also in this compile-time Brainfuck compiler).
There’s some highly redundant wrapper code inside the definition of
If we added another virtual method, we’d have to add another wrapper:
But D has
opDispatch(), which provides a way to automatically add members to a struct. When an
opDispatch() is defined in a struct, any time the compiler fails to find a member, it tries the
opDispatch() template function. In other words, it’s a fallback for member lookup. A fallback to a
return vtable.MEMBER(&this, args) will effectively fill in all the virtual
function dispatchers for us:
The downside is that if the
opDispatch() fails for any reason, the compiler gives up on the
member lookup and we get a generic “Error: no property foo for type Animal”. This is confusing if
foo is actually a valid virtual member but was called with arguments of the wrong type, or
opDispatch() needs some good error handling (e.g., with
An alternative is to use a newer feature of D:
static foreach. This is a powerful tool that
can create declarations inside a struct (and other places) using a loop. We can directly read a list of members
VTable definition by using some compile-time reflection:
The advantage in this case is that we’re explicitly creating struct members. Now the compiler can distinguish between a member that shouldn’t exist at all, and a member that exists but isn’t used properly.
It’s all just like the C equivalent
As I said, this is basically just a tour-de-force of ways that D can improve the code from the previous post.
However, the original motivation for this blog post was people asking me about tricks I used to implement
polymorphic inheritance in bare metal D code, so I’ll finish up by saying this: All this stuff works in
-betterC code, and none
of it requires extra runtime support. The code in this post implements the same kind of thing as in the previous post. It’s just expressed in a more compact and less