Thoughts about in contract inheritance

Timon Gehr timon.gehr at gmx.ch
Wed Feb 29 06:44:07 PST 2012


On 02/29/2012 03:06 PM, Stewart Gordon wrote:
> 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.
>

The front page of the web site is quite explicit about this:

// Interfaces and classes
interface Printable {
     void print(uint level)
     in { assert(level > 0); } // contract is part of the interface
}

// Interface implementation
class Widget : Printable {
     void print(uint level) { ... } // <-- assumed to inherit contract
}

// Single inheritance of state
class ExtendedWidget : Widget {
     override void print(uint level)
     in { /* weakening precondition is okay */ } body { // <-- see here!
          ... level may be 0 here ...
     }
}

Anyway, probably it is not stated explicitly in the relevant parts of 
the spec because it is assumed that the reader is familiar with similar 
features in other languages.

> 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.
>

This is the bug in 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.
>

Probably.

>
> 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.


Not at all. If anything, it would alleviate the issue. Likely, assertion 
failures would be introduced that show that there is a consistency 
problem in the application.

> Though doing and dusting
> http://d.puremagic.com/issues/show_bug.cgi?id=3836
> would alleviate this.
>

Indeed.

> 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
>
> ...

This is not a contract-related problem. It is a breaking API change, 
whether or not the library class defines language level contracts.

>
> But if we avoided this by getting rid of in contract inheritance,

If we want to avoid this we'd have to get rid of inheritance altogether, 
not just contract inheritance. A contract always has a corresponding 
implementation.

> 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?
>

Library writers shouldn't silently change functionality and/or redefine 
interfaces. The new stuff should be introduced under a different name 
and the old name should be deprecated. (As an inferior alternative, the 
library user could just read the change log and notice that there is now 
a problem.)

Anyway, this second scenario has a similar severity under the current 
contract inheritance behavior in DMD 2.058 and the right inheritance 
behavior in a future version of DMD.


>
> 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