I just pushed a change that fixes a long-standing problem with interfaces.
Interfaces are implemented as ordinary annotations. When the @interface
annotation is used, it expands a definition of a class derived from
VTableBase. This lets us mix the interface in with arbitrary base classes
and also lets us define a class with multiple interfaces (diamond inheritance,
where a class inherits from multiple base classes with a common ancestor
class, is not allowed in Crack except for the VTableBase class, so interfaces
can not be derived from Object which classes are by default).
We could just derive from VTableBase except that we still need the reference
counting mechanism defined in Object. For example:
class A {}
class B : VTableBase {}
class C : A, B {}
C c = {};
B b = c;
c = null;
In the example above, when 'c' is assigned to null, the reference count of its
object drops to 0 and the object is deleted because B doesn't have bind and
release operators or a reference count. 'b' now points to unmanaged memory.
Part of what @interface does is to generate bind and release operators that
delegate to Object.oper bind() and Object.oper release(). But to be able to
ues these, we need a way to convert the interface to the Object that its
implementation class will be based on.
As a hack, the code used to generate a special method:
_iface_get$(Interface)Object() ($(Interface) was the name of the interface
class). This was abstract in the interface and defined in the implementation
to simply "return this," allowing us to do the conversion. But _iface_get*
had some problems because it was based on the simple class name. So:
- Aliasing interfaces didn't work, because "@implements Alias" caused
_iface_getAliasObject() methods to be generated instead of
_iface_getRealClassNameObject() methods.
- You couldn't implement two different interfaces with the same simple name,
for example Functor1[void, int] and Functor1[void, String] (for generics,
we only used the name of the generic class, not the instantiation class).
The solution to this is the special "oper from ClassName" operator. Like
"oper to", "oper from" is implemented in the parser and has full knowledge of
the type that is specified. Therefore, it can implement the operator based on
the canonical name of the type, solving the problems above.
I originally considered creating a more complete implementation of virtual
base classes, but with "oper from", I no longer see a use case for it.
I think that everything that you can do with a virtual base class you can also
do with "oper from" and annotations.
Of course, I'm open to a counterexample.