The Non-Virtual Interface idiom in D

Michel Fortin michel.fortin at michelf.com
Sat Sep 26 05:37:01 PDT 2009


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.

Not only could it generate that contract-verifying function by itself, 
but having a separate contract-verifying function you could decide 
whether to evaluate contracts or not when compiling the calling 
function instead of the function you call, which is better in my 
opinion.

About that last example, where you must bypass contracts when 
evaluating your own contract: with the ability to select at the call 
site whether or not you want to evaluates contracts, you could make it 
so that within a contract functions are automatically called without 
contract evaluation. This way you would not have to think too much 
about infinite recursion caused by contracts.


-- 
Michel Fortin
michel.fortin at michelf.com
http://michelf.com/




More information about the Digitalmars-d mailing list