"The last feature": overridable methods in interfaces
Steven Schveighoffer
schveiguy at yahoo.com
Mon Feb 8 12:08:37 PST 2010
On Mon, 08 Feb 2010 14:36:37 -0500, Andrei Alexandrescu
<SeeWebsiteForEmail at erdani.org> wrote:
> Don wrote:
>> Andrei Alexandrescu wrote:
>>> Walter has now implemented final methods in interfaces and also
>>> contracts in interfaces, both of which I think are just awesome.
>>>
>>> We figured that essentially he artificially disallows interfaces from
>>> providing bodies for methods. I think that's a gratuitous limitation;
>>> the only distinguishing quality of an interface is that it has no
>>> state. Other than that, interfaces can always offer overridable
>>> functions that by default offer functionality in terms of existing
>>> interface functions. For example:
>>>
>>> interface Stack(T)
>>> {
>>> void push(T);
>>> void pop();
>>> @property ref T top();
>>> @property bool empty();
>>> T belowTop()
>>> {
>>> auto t = top;
>>> pop();
>>> auto result = top;
>>> push(t);
>>> }
>>> }
>>>
>>> The default implementation of belowTop does a fair amount of work. A
>>> particular implementation might just use that or override it with a
>>> more efficient implementation.
>>>
>>> Many more examples can be imagined, but I'm looking for a killer one,
>>> or perhaps a killer counterexample (e.g. when would an
>>> interface-defined method be really bad?)
>>>
>>> Your thoughts welcome.
>>>
>>>
>>> Andrei
>> I don't understand this. How does belowTop() know how to call top()?
>
> It calls top() through the normal interface mechanism. Inside
> belowTop(), this has Stack!T type.
Actually, I think Don has a point here. A virtual function (even on an
interface) is always called with the 'this' pointer, not the interface
pointer. A real example:
interface A
{
int bar();
int foo() { return bar(); }
}
class C : A
{
override int bar() { return 1;}
}
class D : C
{
override int foo() { return 2;}
}
if you have a reference to A, when calling foo, what do you pass as the
this pointer? I think the way it works is an interface call does an
interface lookup to get the 'true' this pointer (this is a quick lookup
since an interface pointer has the offset info at a predetermined
location), so the object pointer is passed into foo. When the actual type
is a D object, a D reference is expected, but when the actual type is a C
object, what is expected?
The compiler cannot tell what the underlying type is, so when the actual
type is a C object, a C reference will be passed in. So in a "default
implementation", there has to be an implicit thunk to convert the type
back into an interface. Basically, the function foo as implemented in A
looks like this:
int foo() {
A __this = cast(A)this; // do a thunk, 'this' is of type Object
return __this.bar(this); // no lookup of this required, so this is the
same as a standard virtual call
}
This severely lowers my taste for this idea. I think a thunk uses a
linear lookup of the interface list at runtime to find the correct
interface.
A way you might be able to get rid of this problem is to compile the
default implementation as if it were a function of the class that
implements the interface. I could probably live with that, but this
feature seems more complicated than it is worth.
-Steve
More information about the Digitalmars-d
mailing list