The Non-Virtual Interface idiom in D
Andrei Alexandrescu
SeeWebsiteForEmail at erdani.org
Sat Sep 26 07:06:24 PDT 2009
Michel Fortin wrote:
> On 2009-09-25 16:49:27 -0400, Andrei Alexandrescu
> <SeeWebsiteForEmail at erdani.org> said:
>
>> 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.doEquals(cast(T) this) == result);
>> return result;
>> }
>> }
>
> [Note: I corrected the above example by replacing rhs.equals with
> rhs.doEquals.]
>
>> 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?
>
> I think you're writing a lot of boilerplate code for something that the
> compiler should be able to do by itself. I mean, it's a lot cleaner with
> contracts, and there is no reason the compiler couldn't generate itself
> that "contract-verifying" non-virtual function.
I think it would be a mistake to latch on my quick examples. It's not
only about before and after checks, it's more about low-level
customization points versus higher-level interfaces.
Andrei
More information about the Digitalmars-d
mailing list