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