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