The Non-Virtual Interface idiom in D

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Fri Sep 25 13:49:27 PDT 2009


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



More information about the Digitalmars-d mailing list