Michel Fortin wrote:
On 2009-09-25 16:49:27 -0400, Andrei Alexandrescu
<seewebsiteforem...@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