Thread overview
Looking for details of how interface method tables are implemented in D
Jun 17, 2023
Dibyendu Majumdar
Jun 17, 2023
user456
Jun 17, 2023
FeepingCreature
Jun 17, 2023
Dibyendu Majumdar
Jun 18, 2023
FeepingCreature
Jun 23, 2023
Dibyendu Majumdar
Jun 23, 2023
FeepingCreature
June 17, 2023

Hi

I am looking for details of how interface method dispatch works in D.
I would be grateful for any documentation of code references I can lookup.

In particular, I wanted to understand how similar / different the implementation is compared to Java.

Regards
Dibyendu

June 17, 2023

On Saturday, 17 June 2023 at 12:34:41 UTC, Dibyendu Majumdar wrote:

>

Hi

I am looking for details of how interface method dispatch works in D.
I would be grateful for any documentation of code references I can lookup.

In particular, I wanted to understand how similar / different the implementation is compared to Java.

Regards
Dibyendu

That is specified here. So you have additional dereference to access the vtbl of an interface (vs class vtbl). Then an address is read in this table, cast to a function type, then called like a standard virtual call.

June 17, 2023

On Saturday, 17 June 2023 at 12:34:41 UTC, Dibyendu Majumdar wrote:

>

Hi

I am looking for details of how interface method dispatch works in D.
I would be grateful for any documentation of code references I can lookup.

In particular, I wanted to understand how similar / different the implementation is compared to Java.

Regards
Dibyendu

Note: While writing this answer, I found the actual specified answer in the D ABI docs: https://dlang.org/spec/abi.html#classes

I still think this explanation is good though.


I don't know for sure, but I think pretty much every single-inheritance with interface implementation in a C-like language works like this:

You have a class C. C has a vtable of dynamic methods:

C {
  C_VTable* __vtable;
  classdata goes here
}
C_VTable {
  void function(void*) method1;
  void function(void*) method2;
  void function(void*) method3;
}

You have a class D that inherits from C. It starts with a pointer to a D_VTable, that looks like this:

D_VTable {
  // all methods that D overrides are replaced in the C part
  C_VTable parent;
  // methods that only appear in D go here
  void function(void*) method4;
}

It has to be like this, so that you can take a pointer to D and implicitly treat it as a pointer to C.


Now what about interfaces? They're a bit complicated.

Obviously an interface pointer cannot be the same pointer as the class pointer of the class that implements it. Because the interface methods would have to be at a fixed offset from the start of the vtable, and then they could collide with methods added by the class. So an interface reference is an additional vtable pointer in the object, that points at a dedicated interface vtable. That vtable usually also has the offset from the vtable pointer to the start of the object, because we need that to get the object reference back so we can actually call methods with it.

C : I
{
  C_VTable* __vtable;
  C data goes here.
  // I i = c; results in a pointer *to this field.*
  I_VTable* __i_vtable;
}

I_VTable {
  size_t i_to_c_offset = -20; // or whatever
  void function(void*) i_method_1;
  void function(void*) i_method_2;
  void function(void*) i_method_3;
}

Anyway, how does all that compare to Java? No clue! Sorry. I can only assume it's pretty similar, because this is really is the "unambiguously sensible" way to do it.

June 17, 2023

On Saturday, 17 June 2023 at 17:16:16 UTC, FeepingCreature wrote:

> >

I am looking for details of how interface method dispatch works in D.

>

Note: While writing this answer, I found the actual specified answer in the D ABI docs: https://dlang.org/spec/abi.html#classes

Anyway, how does all that compare to Java? No clue! Sorry. I can only assume it's pretty similar, because this is really is the "unambiguously sensible" way to do it.

It seems closer to C++ design, as Java does not adjust an object pointer when casting to an interface or subtype.

June 18, 2023

On Saturday, 17 June 2023 at 20:29:35 UTC, Dibyendu Majumdar wrote:

>

On Saturday, 17 June 2023 at 17:16:16 UTC, FeepingCreature wrote:

> >

I am looking for details of how interface method dispatch works in D.

>

Note: While writing this answer, I found the actual specified answer in the D ABI docs: https://dlang.org/spec/abi.html#classes

Anyway, how does all that compare to Java? No clue! Sorry. I can only assume it's pretty similar, because this is really is the "unambiguously sensible" way to do it.

It seems closer to C++ design, as Java does not adjust an object pointer when casting to an interface or subtype.

Ah, GPT-4 (and then Google) points me at https://wiki.openjdk.org/display/HotSpot/InterfaceCalls (It is impossible to directly google 'java interface implementation' because the results are far, far too flooded with beginner tutorials.)

To summarize, it looks like Java can do interface calls on the same reference as the object mostly by paying a lot of runtime cost to find the actual method in question. In comparison, the D approach can just call the interface method at a fixed vtable offset, as it does with class methods. Once the runtime has the interface vtable, calls proceed as in D.

I think comparatively, Java can more readily commit to overhead costs for interface resolution because in inner loops it expects to find a deterministic object type and create a direct call anyways. D has to compile in one shot and be done, so it has to be fast from the start.

June 23, 2023

Follow up question.

If a class implements 5 interfaces.

I create an object of this class.

Is it correct that the resulting object has 6 vtable pointers embedded, one for the class, and 5 for the interfaces?

And every object that is allocated will have this overhead?

In Java land, no vtables are embedded in the object.

June 23, 2023

On Friday, 23 June 2023 at 09:53:25 UTC, Dibyendu Majumdar wrote:

>

Follow up question.

If a class implements 5 interfaces.

I create an object of this class.

Is it correct that the resulting object has 6 vtable pointers embedded, one for the class, and 5 for the interfaces?

And every object that is allocated will have this overhead?

In Java land, no vtables are embedded in the object.

Yep, that's correct. Though note this only applies to interfaces that are direct parents of the class; interfaces that are parents of other interfaces don't count. However conversely you do still need space for the interface pointers of your superclass.

Java is a dynamically compiled language. This allows it to take liberties that are simply unfeasible for a statically compiled language. D cannot specialize a method call for a particular class at runtime; it has to be fast on its first execution, and every successive one. So trading off space for speed makes sense here.

That said, if you're creating an object with six interfaces, which you are instantiating so often that its size matters, you're almost certainly writing unidiomatic D. Keep in mind that if you write D as if it was Java, you will be setting yourself up for GC and performance pain down the road.