"The last feature": overridable methods in interfaces

dsimcha dsimcha at yahoo.com
Mon Feb 8 12:48:57 PST 2010


== Quote from Andrei Alexandrescu (SeeWebsiteForEmail at erdani.org)'s article
> 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

If we're going to do this, then why not allow (biggest oxymoron of all time)
concrete interfaces, i.e. interfaces that can be instantiated?  This would be
useful for things like the template method pattern.  Example:

/**Reduction implemented by template method pattern.*/
interface Reduce(T, U) {
    T opCall(T initialValue, U[] array) {
        T result = initialValue;
        foreach(elem; array) {
            result = reductionFunction(result, elem);
        }

        return result;
    }

    abstract T reductionFunction(T, U);
}

interface Sum(T, U) : Reduce!(T, U) {
    override T reductionFunction(T lhs, U rhs) {
        return lhs + rhs;
    }
}

An instantiation of an interface wouldn't perform any heap allocations and would
just return a pointer to the relevant vtable.  It would then work just like an
interface inherited from a class:  Calling a method dispatches based on the vtable
logic.  The this pointer is simply a pointer to the relevant vtable.  With the
this pointer in hand, the function can call other virtual functions just like a
regular class.



More information about the Digitalmars-d mailing list