"The last feature": overridable methods in interfaces

Steven Schveighoffer schveiguy at yahoo.com
Mon Feb 8 09:02:58 PST 2010


On Mon, 08 Feb 2010 00:37:53 -0500, Andrei Alexandrescu  
<SeeWebsiteForEmail at erdani.org> 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.

You forgot to return result :)

Also, it should be implemented like this to prevent a problem where a  
stack with a single element is cleared before an exception is thrown.

T belowTop()
{
   auto t = top;
   pop();
   scope(exit) push(t);
   return top;
}

As another example (not sure if it's "killer"), here is a more useful  
default method:

T popTop()
{
    scope(success) pop();
    return top;
}

I can see real use for "give me the top, and pop it off at the same  
time."  Now, if we make popTop final, it's 2 virtual function calls  
(popTop can be inlined), but if we make it overridable, the default  
implementation has 3 virtual calls, but can be optimized into 1 virtual  
call if so desired.  I guess it's a tradeoff between whether you think  
most implementors will prefer to use some default implementation or most  
will want to optimize.  But in the case you expect most to optimize,  
wouldn't you just provide no implementation?  In the case of popTop, it's  
attractive to say "your stack class only needs to define these few  
primitives," but it's generally trivial to provide a popTop implementation  
that is more optimized.

I've seen places where interface documentation says "implement this  
function like this: ..." which is quite annoying.  final functions solve  
most of these, I'm not sure if we need another way to do it, but I can't  
see any reason why it should be disallowed.  The judgement call of whether  
to provide an overridable implementation and no implementation would be  
difficult.  I don't see a default-but-overridable implementation being  
used often.

-Steve



More information about the Digitalmars-d mailing list