The Non-Virtual Interface idiom in D

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Sat Sep 26 10:07:29 PDT 2009


Jeremie Pelletier wrote:
> Andrei Alexandrescu wrote:
>> In this article:
>>
>> http://www.gotw.ca/publications/mill18.htm
>>
>> Herb Sutter makes a powerful argument that overridable functions 
>> (customization points) should actually not be the same as the 
>> publically available interface. This view rhymes with the Template 
>> Method pattern as well.
>>
>> This leads to the interesting setup in which an interface should 
>> ideally define some signatures of to-be-defined functions, but 
>> disallow client code from calling them. For the clients, the same 
>> interface should expose some higher-level final functions.
>>
>> Ignoring for the moment access protection semantics in D (which are 
>> broken anyway), let's say this would work:
>>
>> interface Cloneable(T) if (is(T == class))
>> {
>>     private T doClone(); // must implement but can't call
>>     T clone()            // this is what everybody can call
>>     {
>>         auto result = doClone();
>>         assert(typeof(result) == typeof(this));
>>         assert(this.equals(result));
>>         return result;
>>     }
>> }
>>
>> So clients must implement doClone, but nobody can ever call it except 
>> Cloneable's module. This ensures that no cloning ever gets away with 
>> returning the wrong object.
>>
>> Pretty powerful, eh? Now, sometimes you do want to allow a derived 
>> class to call the base class implementation. In that case, the 
>> interface function must be protected:
>>
>> interface ComparableForEquality(T)
>> {
>>     protected bool doEquals(T);
>>     final bool equals(T rhs)
>>     {
>>         auto result = doEquals(rhs);
>>         assert(rhs.equals(cast(T) this) == result);
>>         return result;
>>     }
>> }
>>
>> The difference is that now a derived class could call super.doEquals.
>>
>> This feature would require changing some protection rules, I think for 
>> the better. What do you think?
>>
>>
>> Andrei
> 
> What about:
> 
> interface ComparableForEquality(T) {
>     bool equals(T rhs)
>     out(result) {
>         assert(rhs.equals(cast(T)this) == result);
>     }
> }

I want to cajole Walter into implementing contracts on interfaces as well.

> Getting instead a contract that gets added to implementations, or at 
> least only the base implementation, and letting the actual method 
> unimplemented.
> 
> However having code for interfaces as well as protection would be neat. 
> They could prevent a lot of template mixins within every implementation 
> to get a common feature.

Note that NVI is about more than pre- and post-conditions. I'm actually 
amazed that so many people latched so firmly onto the examples I gave 
(as opposed to e.g. the examples in Herb's article).


Andrei



More information about the Digitalmars-d mailing list