Thoughts about in contract inheritance
Stewart Gordon
smjg_1998 at yahoo.com
Wed Feb 29 06:06:33 PST 2012
There's been a lot of debate about the inheritance of in contracts, in particular what's
supposed to happen if a method in a base class has an in contract and its override doesn't.
http://d.puremagic.com/issues/show_bug.cgi?id=6856
The spec isn't explicit on whether the overridden method retains the base's in contract
unchanged or loses its in contract altogether.
Some claim that the absence of an in contract is just syntactic sugar for an empty in
contract, in which case the override loses the in contract (can be called with any
arguments of the correct types). This is the view taken by DMD.
But others claim that you shouldn't have to specify an in contract in order to inherit the
one you already have, and that if you want to remove it altogether then you should have to
do it explicitly.
What's more, there's a hole in the current equivalence between no in contract and an empty
in contract: in only the former case does the compiler reject an in contract on an
override further down the hierarchy. This will want to be fixed if an explicit empty in
contract becomes the only way to lift all argument restrictions when overriding a method.
Moreover, there are hijacking vulnerabilities.
http://dlang.org/hijack.html
addresses the danger that a derived class may define a method, and then a later version of
the base class coincidentally defines a method with the same name but different semantics.
Further problems in this area would ensue if the default behaviour were to pass through
the base class's in contract unchanged. Though doing and dusting
http://d.puremagic.com/issues/show_bug.cgi?id=3836
would alleviate this.
Another scenario I've thought of is:
- library class defines a method with an in contract
- application class overrides this method, and has the same argument restrictions as the
library class
- a later version of the library class widens the range of acceptable inputs
- however, the app's override is not prepared to deal with inputs that are newly allowed
by the API
I don't know if there's a way to deal with this short of doing away with in contract
inheritance altogether. Of course, the app programmer could protect against this by
duplicating the contract checking in the body of the method, and doing so would even show
whether the input to the function was actually outside the range allowed by the API or
merely outside the range that the app class's version of the method can deal with. But
it's better not to have to duplicate code like this.
But if we avoided this by getting rid of in contract inheritance, it might just lead more
programmers to break the inheritance model by forbidding operations on objects of the
derived class that are allowed on objects of the base class. I suppose this is a variant of
http://en.wikipedia.org/wiki/Circle-ellipse_problem
It would also get in the way of another proposal I'm inclined to agree with, that anything
that calls a method on an object reference of the base class type should be required to
adhere to the base class's API, of which the in contract is a part.
http://d.puremagic.com/issues/show_bug.cgi?id=6857
(see also the thread "define in contract according to the caller, not the callee." on this
'group)
Still, is there a good way of dealing with the scenario I've brought up here?
Another thing that's needed for a robust DbC system in D:
http://d.puremagic.com/issues/show_bug.cgi?id=6549
Stewart.
More information about the Digitalmars-d
mailing list