API Design Myth: Interface as Contract


I often hear people saying that interfaces specify contracts. I believe this is a dangerous myth. Interfaces, by themselves, do not specify much beyond the syntax required to use an object. The interface-as-contract myth causes people to do the wrong thing when trying to separate contracts from implementation, which is a good engineering practice. Interfaces separate syntax from implementation, which is not that useful, and the myth provides a false sense of doing the right engineering.

Contract is semantics — and these can actually be expressed with what many unjustifiably consider unwanted implementation. For example, the contract of IList<T> says that when an item is added to the collection, the Count property is incremented by one. Such simple contract can be expressed and what’s more important locked for all subtypes, using something like the following abstract class.

public abstract class CollectionContract<T> : IList<T> {
    public void Add(T item){
        AddCore(item);
        this.count++;
    }
    public int Count {
        get { return this.count; }
    }
    protected abstract void AddCore(T item);
 
    private int count;

    …
}

Comments (10)

  1. I always thought the real problem was the change in the meaning of the word "interface": it used to mean contract. Then after interfaces were added to languages, such as the C# concept of interface, the word became tied to a specific type of interface. It was no longer generic.

    I still use the word "interface" to mean "contract" in conversation sometimes, but it cause a lot of confusion. People assume I mean a C#-type interface. So I must specify contract…. 🙁

  2. Daniel Moth says:

    As soon as you went into the example my brain told me I was about to encounter postcondition syntax…but I didn’t. Are you guys even remotely considering adding some pre/post-condition support and invariants much like what Eiffel offers? Only then, I think, we would really be talking about contracts.

  3. Actually the way you have described a contract is not how its described as all over in the msdn. I think that is why we, the readers of msdn, fall victim of this myth. I’m going to refer *some* of the places where I thought that interface is a contract(words between "—><—" are excerpts from the msdn pages/articles):

    page:ms-help://MS.MSDNQTR.2003FEB.1033/dncomg/html/msdn_design.htm —>

    Each interface must have a GUID that serves as its programmatic name. It is this interface ID (IID) that uniquely identifies the contract defined by the interface. After an interface design with a particular IID is published, the specifics of all the other elements (described in detail below) that make up that interface cannot change . . . ever. (By published, we mean implemented in a binary component and "released" to another party to use.) <—

    —>A rigid contract requires that all methods be fully implemented.<—

    page:ms-help://MS.MSDNQTR.2003FEB.1033/dndotnet/html/callnetfrcom.htm

    —>The contract says that the class will implement all of the members of the interface. It may also contain additional members that are not part of the interface, but you’ll get an error if you try to build a class that does not completely implement an interface.

    <—

    while defining the "Interface Inheritance" the article says —>When you want to create an abstract class, you use the keyword Interface instead of Class. You give the interface a name, and define each of the properties and methods that you expect a subclass to implement. The reason you do this is that there is nothing in the base class that would make sense to implement—it only contains generic data without methods. You are just creating a contract that says any subclass using this interface must adhere to certain rules.<—

    what are those rules? the logic that should be found in the implementation of the interface in a class OR just following a syntax?

    page:ms-help://MS.MSDNQTR.2003FEB.1033/vbcn7/html/vaconInterfacesInVisualBasic70.htm

    —>An interface represents a contract, in that a class that implements an interface must implement every aspect of that interface exactly as it is defined.<—

    —>If you think of an interface as a contract, it is clear that both sides of the contract have a role to play. The publisher of an interface agrees never to change that interface, and the implementer agrees to implement the interface exactly as it was designed.<—

    So I always thought that they are only talking about function-signatures/syntax.

  4. One of my favorite development practices is stubbing things out. I don’t know if I’d go so far as to calling it "mocks", or "development by contract", but it can allow developers with dependancies to move forward until the real subsystem comes on line. But this bring about a corollary favorite development practice: tell me where it hurts. More specifically, if you haven’t finished implementing something, but have methods in place, don’t just have them return null, or silently exit….

  5. I agree that the interface by itself is not enough to specify a contract. I like to write unit tests against my interface in order to specify its dynamic behavior. Then, a build against an implementation will both compile the class against the interface checking its structure, as well as run the tests thus verifying its behavior. I’ve written about this here:

    http://udidahan.weblogs.us/2006/05/06/behavior-specification-the-next-generation-of-unit-testing/

    Since you’ll want client code to depend only the interface, not on some abstract base class for reasons of extensibility, this approach documents for that client code what assumptions in can make.

    So, I’d have to say that interfaces are a necessary part of the solution, but not sufficient by themselves.

  6. Udi, having a set of reference tests for abstractions is a great idea.

    But I don’t see why interface gives you more/better extensibility than an abstract class, besides cases where you need “multiple inheritance.”

  7. deepak N says:

    kcwalina, another very  good part of interface is we can use it to ensure proper/effective naming in our code.

    if we can identify similarities (properties/functions/events) between related or unrelated classes then we can prepare a interface with those functions/properties and make it a practise to implement appropriate interface when those properties and functions are used.

    this will make sure we are not using different names for similar funtions/ properties

    eg. i may have 3 classes Circle/RoofTop/Carpet

    its usefull to implement IhaveArea interface and then implement the GetArea() function of the Interface. This will make sure even if differnet people are working on the project they all have identical names for similar work.

  8. Sam Goldmann says:

    While I would agree that contract is semantics, contracts usually specify terms and conditions on an agreement, and not the methods by which those terms and conditions are satisfied. Your example above does much more than introduce “unwanted implementation”- it grossly violates the tenet principle conventionally called (oddly enough) “separation of implementation and interface”.

    In computer science and software engineering, the terms and conditions on a contract are typically referred to as pre- and post-conditions. While abstract classes could be used to validate that these conditions are satisfied through the use of the template-method pattern, this approach can introduce unacceptable run-time overhead even when limited to debug builds.  Most importantly the design decision to use abstract classes has an enormous consequence on design in languages that don't allow for multiple inheritance such as C#. As Udi Dahan pointed out above, unit testing is the most appropriate place to validate that contracts are being honored.

    Your example above does much more than merely express the requirement that “when an item is added to the collection, the Count property is incremented by one”. It forces that :

     1) The count be an explicitly maintained integer field.

     2) The count be maintained in a field which is a private member of CollectionContract.

    Your bold assumptions as to how CollectionContract will be used has made it rigid and inflexible.

    Interfaces are much more than merely syntax. At the end of the day, the machine doesn't care what label you assign a method. That label is intended for a human being.  A method to add an object to a collection is typically called “Add” because that is what it does, thus communicating semantics. If the contract needs further specification, comments are a powerful tool which are well supported by and integrated into most modern development environments.

    Despite the age of this article, I felt compelled to reply, as this sort of thinking merely reinforces the naïve decisions commonly made by novices. I find that poor design decisions motivated by misguided principles proliferate many frameworks and libraries. Such misinformation serves only to frustrate developers and limit the availability of quality software.

  9. Gary says:

    Interfaces approach contracts as implementations reduce statefulness.  Thus, a stateless implementation's contract would be perfectly described by an interface, otherwise you have to do the precondition/postcondition stuff.