Want to read Slashdot from your mobile device? Point it at m.slashdot.org and keep reading!

 



Forgot your password?
typodupeerror
×
Programming

Why Is "Design by Contract" Not More Popular? 178

Coryoth writes "Design by Contract, writing pre- and post-conditions on functions, seemed like straightforward common sense to me. Such conditions, in the form of executable code, not only provide more exacting API documentation, but also provide a test harness. Having easy to write unit tests, that are automatically integrated into the inheritance hierarchy in OO languages, 'just made sense'. However, despite being available (to varying degrees of completeness) for many languages other than Eiffel, including Java, C++, Perl, Python, Ruby, Ada, and even Haskell and Ocaml, the concept has never gained significant traction, particularly in comparison to unit testing frameworks (which DbC complements nicely), and hype like 'Extreme Programming'. So why did Design by Contract fail to take off?"
This discussion has been archived. No new comments can be posted.

Why Is "Design by Contract" Not More Popular?

Comments Filter:
  • Design by Contract (Score:3, Informative)

    by VGPowerlord ( 621254 ) on Saturday March 10, 2007 @03:29AM (#18298080)
    Design by Contract adds more complexity to code, particularly if you're dealing with a language that doesn't natively support it.

    Of course, you don't actually need special constructs to check values on input then tossing an exception/returning an error when the data is not in the expected range. In fact, you should go back to remedial programming classes if you're not already doing this.

    The last thing you should do is try to figure out what the caller really meant if the value is out of range. Assuming a default works in some cases (which, btw, wouldn't work with Design by Contract as I understand it), but most of the time it's just better to fail and make the programmer fix their mistake.
  • by Animats ( 122034 ) on Saturday March 10, 2007 @03:48AM (#18298140) Homepage

    If you're serious about design by contract, you need to use a language that supports it. Eiffel does, of course, and so does "Spec#", Microsoft's verifiable variant of C#, [microsoft.com] but other than that, "support" is a collection of half-baked add-ons that don't provide any strong assurances.

    If you're going to take object invariants seriously, you have to take object invariance seriously. Objects can't be allowed to change other than when control is inside them, and when control is inside the object, no public method of the object can be called. This means you have to be able to catch cases where object A calls object B which then calls a public method of A. The invariant of A isn't established at that point, and so, calls into A are illegal. This strict notion of inside/outside is fundamental to class invariants, but many so-called "design by contract" approaches gloss over it. You need a way to explicitly say "control is now leaving this object temporarily" when calling out of an object, and the object's invariant must be true at that exit.

    Threading and locking have to be handled in the language. The language needs to know which locks protect what data, or invariants aren't meaningful.

    Then there's the problem of how to express an invariant, entry, or exit condition. Are quantifiers provided, or what? How do you talk about concepts like "forward and back pointers of the tree must be consistent"? There's known formalism for that sort of thing, but it's not something you can express cleanly in, say, C or C++.

    Without smarts in the compiler, run time checking tends to be too expensive. The compiler needs to know that member function F can't change member variables X and Y, and therefore, invariants concerning X and Y don't have to be rechecked. Without optimizations like that, you end up rechecking everything on every call to every access function.

    I'd like to see more design by contract, and I'd like to see it work well enough that when something breaks, you know which side of the interface to blame. I used to do proof of correctness work, and it's quite possible to do this. But you can't do it in C or C++; the languages are too loose. It's been done well for Modula and Java, and a DEC R&D group had a very nice system going just before Compaq canned DEC's Palo Alto research labs. The rise of C killed off verification work; the decline of C may bring it back.

  • Already mostly done (Score:4, Informative)

    by Todd Knarr ( 15451 ) on Saturday March 10, 2007 @05:45AM (#18298452) Homepage

    As has been noted, most programmers already do design-by-contract, they just don't call it that. They call it argument checking. The first thing most routines do is validate their arguments, and return an error if any of them are invalid. The last thing done is to check the results and return an error if the results aren't valid. The calling code then checks for error codes or invalid results (eg. a search function returning a null pointer indicating the item wasn't found).

    In the real world I often skip this overhead when the conditions are enforced elsewhere. For example, a data structure needed by an internal function may not have to be checked for existence since if it hadn't been created my initialization function would've detected this and signaled an error and the program would've exited. In cases like that, I either omit the check or wrap it in an ifdef so it's only done during development and ignored by the compiler during the release build.

    Don't make the mistake of confusing the name of a concept with the concept itself. You'll find quite often that that nifty shiny-new concept someone's presenting as their own has actually been around for 30-40 years and they've just added some chrome, filed off the serial numbers and changed the name to keep you from noticing this.

  • by smcleish ( 118335 ) on Saturday March 10, 2007 @06:59AM (#18298652) Journal
    I do some teaching on an Open University course here in the UK which uses the concept, and my experience is that many students, including experienced programmers, find it difficult to do. Common errors include:

    - confusing the signature of the function (in terms of the types of permitted input) with the pre-condition. It may be true for some implementations of pre-conditions that you need to include information of the form "input is a string" but it isn't for the way we do it in the course.
    - ignoring input cases (e.g. giving a post-condition which only makes sense when the input is a non-empty string, but using a "true" pre-condition); students know theoretically that every possible permitted input needs to have an appropriate output in the post-condition but can't put this into practice
    - difficulty in creating conditions which are precise; this is both in the early part of the course, which uses English language conditions, and later on when algebraic conditions are introduced
    - designing tests which use inputs which fail the pre-condition (which is partly because the testing tool used in the course doesn't check the validity of the pre-condition, so invalid inputs can produce sensible looking outputs)
    - confusion between pre- and post- condition rules: they often want to restrict the input by changing the post condition

    It seems to be the case that it is at a particular level of abstraction vs practicality that many find difficult to cope with.
  • by Coryoth ( 254751 ) on Saturday March 10, 2007 @07:22AM (#18298746) Homepage Journal

    I don't want my software to fail in the field (at my day job, we write stock trading software - reliability is key because lack of availability can quickly become very expensive). If I could define a number of pre- and post-conditions for each function and have the compiler check these for me, I'd be happy.
    And indeed, this can be done, and is available for a number of DbC systems. Check out JML which has ESC/Java2 to provide static contract checking for Java, Spec# (C# with contracts) which uses the Spec# verifier for static checking of contracts, and Eiffel with ESpec-Verify for static checking of Eiffel contracts.

    If the conditions are only going to be checked at runtime, then I'm going to have to write unit tests anyway - otherwise, the failure's going to be beautifully detected and localised and so forth, but crucially, it's going to be one of my customers that detects it. If I'm writing unit tests anyway, why bother with DbC?
    The difference between DbC and unit tests (and really, you should be doing both) is that if a test can be expressed as a constraint then it is useful to simply express that as a contract, while if the test is a specific input to output matching test then it is going to be useful as a separate unit test. When you run your unit tests the contract constraints will automatically get checked. More importantly they will help isolate exactly where the error occured when testing integrated systems. Furthermore, by putting constraints as contracts you have improved your API documentation (any decent DbC system includes automated inclusion of contract information in API documentation) which helps other people use your code correctly, and makes maintenance easier.

    Finally contracts allow automated testing. That's where you automatically generate data to pass to the code and let the contracts act as a test oracle to catch and locate problems. With something like AutoTest for Eiffel the data generation can be purely random (constrained by preconditions of course), or designed to sample the input according to best coverage via genertic algorithms, etc. The result is that you find corner cases that you might not have anticipated with your unit tests - and you would be surprised how often that happens, AutoTest found a number of subtle bugs in Eiffel's base libraries which had been production code for years.

    When there's a DbC language or add-on that checks the contracts at compile time, I'll be interested.
    Then you really need to check out JML [iastate.edu] and ESC/Java2, and Spec# [microsoft.com], because you would be interested.
  • Or, better yet... (Score:5, Informative)

    by Chemisor ( 97276 ) on Saturday March 10, 2007 @10:21AM (#18299438)
    > assert(condition) is your friend.

    And assert(condition && "Explanation of why it's bad and what to do to fix it") is even better. Don't make me read your code and figure out why the hell you put some obscure assert(n != 455) in there.
  • by Coryoth ( 254751 ) on Saturday March 10, 2007 @12:19PM (#18300110) Homepage Journal

    By whom? I'd like to look into it for my Java projects.
    DEC R&D made ESC/Java (Extended Static Checking for Java) that used a theorem prover and specification annotations to verify contracts. Development stopped, but it is now open source as ESC/Java2 [secure.ucd.ie] which uses JML [iastate.edu] as annotation markup. I actually listed this as the Java DbC implementation in the article description.

All seems condemned in the long run to approximate a state akin to Gaussian noise. -- James Martin

Working...