According to Frank Heckenbach who cites "Java in a Nutshell":
[...] While an 'abstract' class may define some 'abstract' methods and some non- 'abstract' methods, all the methods defined within an interface are implicitly 'abstract'. [The 'abstract' keyword can, but doesn't have to, be omitted.] [Note: In Java, all methods are what we call virtual.] [...]
So what can we do with an interface? Just as a class 'extends' [is derived from] its superclass, it also optionally 'implements' an interface. 'implements' s a Java keyword that can appear in a class declaration following the 'extends' clause. 'implements' should be followed by the name of the interface that the class implements. In order to implement an interface, a class must first delcare the interface in an 'implements' clause, and then it must provide an implementation (i.e. body) for all of the 'abstract' methods of the interface.
[...]
As I understand this, the Interface mechanism is MI with the following requirements:
* Each object type has one "primary ancestor"; possible other ancestors are "secondary".
* Definition: An object type which does not have data fields, but only abstract (virtual) methods qualifies as an "interface".
* The primary ancestor of an object may be any object; secondary ancestors must be interfaces.
This implies:
* MI among interfaces works without restrictions.
* Instances of interfaces are useless.
* You cannot inherit data fields and function bodies via MI.
* MI does no more cause all those catastrophies as it would be the case with unrestricted MI among "real" objects.
Making these rule obligatory, it would be save to introduce MI into GPC, thus introducing interfaces without needing another keyword. (Just an idea.) However since Delphi seems to have interfaces, we should use their syntax rather than inventing another one. (Just another idea.)
(* Hmm ... the above rules for "careful use of MI" could be useful for *) (* C++ programmers ... perhaps we should tell them? :*)
Concerning a possible implementation in gpc:
AFAICS, the only thing that really makes problems are variables (or parameters) of interface types.
What's the problem? An instance of an interface would be an empty object, containing nothing besides the VMT pointer.
First of all, since interfaces can't be instantiated, such variables or parameters must be pointers (or var parameters). In Java, this is implied, since *all* object variables are pointers.
Do you mean: If an object implements an interface (in Java sense) it must always be accessed through a pointer? If so, why?
But such a pointer must point to the actual object and to the methods declared in the interface. Since different object types can implement the same interface, those methods will not always be at the same VMT offset. However, it is possible to guarantee that all methods of one interface are at consecutive VMT offsets (in the order they're declared in the interface). (*, see below)
So one needs the VMT offset of the interface's first method.
I can see (at least) two solutions:
A "pointer" to an interface variable consists of two parts: the actual pointer to the variable, and the VMT offset of the first method (or, alternatively, directly the adress of the first method in the VMT).
Disadvantage: The pointer gets twice as big. The difference must be considered when assigning it to another pointer (this could be an untyped pointer or a pointer of one of the "parent" interfaces - in the latter case the VMT offset has to be adjusted).
I'm afraid we can forget about this for that reason.
- The VMT must contain information about all interfaces that are implemented together with the addresses of their methods. However, since different object types can implement different interfaces, and one type can implement more than one interface, I can't think of a method that doesn't involve some kind of searching (searching the wanted interface out of possibly many interfaces).
That's the problem why I initially asked about MI.
Does anybody know how C++ solves that problem? Or Java? Or Delphi?
So this is basically a speed vs. size tradeoff. For most applications, I think, speed is to be favoured (and 32 bit programming favours speed, anyway), so I'd prefer the first solution. I can't see a solution without a need of either searching or additional data *per variable* (whereas additional data per VMT wouldn't matter so much).
I agree. Calling virtual methods works quite fast as it is implemented now. If having interfaces (or MI in general) would slow this down, I would vote against it.
But this is quite an interesting problem - not a technical one, how to implement this-or-that without interfering with that-or-this syntax from another dialect. Here we have a problem where it is not even clear that a fast (i.e. O(1)) solution exists. :-(-:
Yours,
Peter
Dipl.-Phys. Peter Gerwinski, Essen, Germany, free physicist and programmer peter.gerwinski@uni-essen.de - http://home.pages.de/~peter.gerwinski/ [970201] maintainer GNU Pascal [970510] - http://home.pages.de/~gnu-pascal/ [970125]