Page 1 of 1

Implementing Interfaces

Posted: Mon Jul 06, 2009 10:55 pm
by JohnnyTheDon
I am currently working a compiler, and would like to add support for an 'interface' construct. Anyone who has programmed C# or Java should be familiar with these. I've thought of a few ways of implementing them, and some input would be nice.

My first method involves having multiple virtual function table pointers. Each interface that the object implements would get a virtual function table pointer, and any pointer to the object typecasted as the interface would point to the virtual function table for that interface. To accomodate for the pointer offset, there would be several entry points into each function as needed that would adjust the 'this' pointer. For example:

Code: Select all

someFunc_InterfaceEntryPoint:
  sub rcx,8
someFunc:
  ret
The virtual function table pointed to by the interface pointer would point to someFunc_InterfaceEntryPoint instead of someFunc. This would also work when a class implements multiple interfaces with the same function, because you could just add another interface entry point.

The other method I have been considering involves extending the size of interface pointers. Instead of just being a pointer to the object, it would also contain a pointer to the virtual function table that implements the interface for that particular object. Function entry points would be found through the virtual function table and then called with the pointer of the object.

I am leaning towards the first method because it doesn't make every pointer twice as large, and only takes up an extra pointer in each object for each interface. Most classes that implement interfaces wouldn't have a ton of instances (for example, you probably won't have your Vector class implement interfaces) so I don't think it would waste much memory.

Re: Implementing Interfaces

Posted: Mon Jul 06, 2009 11:27 pm
by Colonel Kernel
Is the compiler for your own language?

The first technique you described is how C++ compilers typically implement multiple inheritance. I've heard that the second technique is used by some JVMs. In my own OS, I use the second technique explicitly in C to support interface-based polymorphism.

I've grown to like the "fat pointer" technique, since it lets me implement interfaces with or without objects. I can just leave the object pointer in a "fat pointer" as null, as long as the functions in the dispatch table can deal with it.

Which technique is better for you depends on the design of your language. Can you tell us more about it?

Re: Implementing Interfaces

Posted: Tue Jul 07, 2009 1:30 am
by JohnnyTheDon
Of course. It compiles to a virtual machine that I am developing in tandem with the language. Most of the language features (classes, interfaces, etc.) are supported by the virtual machine and are implemented when the code goes through dynamic translation.

As far as classes and interfaces are concerned, it is much like C#. Classes have single-inheritance and can implement interfaces. By default memory is managed by a garbage collector, but pointers and other forms of memory management are still supported. Also like C# there is a difference between reference types (classes) and value types (structures). However, a structure can be explicitly constructed as a reference type, and a class can be explicitly constructed as a value type. Structures have single-inheritance, but not polymorphism.

Pure functions and programming by contract is supported, but neither of these seem like they would affect polymorphism. Interfaces are allowed to place preconditions and postconditions on functions, but that is all done at compile time.

One part of the language that makes good implementation of polymorphism important is support for sharing objects across program boundaries. By changing the virtual function table pointers, normal function calls to an object or interface can be redirected to IPC or the network.

I just thought of supporting both methods and allowing the choice to be made by users and/or the platform, since the code (in most cases) goes through dynamic translation. For example, the first method (which requires less registers) could be used on x86 computers that have few registers, and the second method could be used on platforms with more registers like RISC processors.

Re: Implementing Interfaces

Posted: Sun Jul 12, 2009 8:02 am
by Owen
The way C++ does it is somewhat like this

struct Object {
Class1Vtable* vt1;
Class1Members memb1;

Class2Vtable* vt2;
Class2Members memb2;
}

struct Class1Vtable {
size_t offset;
void* function1;
void* function2;
}

struct Class2Vtable {
size_t offset;
void* function1;
void* function2;
}

To cast a pointer from the class to an interface, you add it's offset. To cast from the interface to the class, you subtract it's offset. I'm not sure which side does the fixup to get the object's this in C++; In a VM, I'd be tempted to have my virtual call instruction do the fixup.