Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I recently discovered Design by Contract (DbC) and I find it an extremely interesting way to write code. Among other things, it would seem to offer:

  • Better documentation. Since the contract is the documentation, it's impossible for one to be out of date. Additionally, because the contract specifies exactly what a routine does, it helps to support reuse.
  • Simpler debugging. Since program execution stops the moment a contract fails, errors can't propagate, and the specific assertion violated will presumably be highlighted. This offers support during development and during maintenance.
  • Better static analysis. DbC is basically just an implementation of Hoare logic, and the same principles should apply.

The costs, in comparison seem to be rather small:

  • Extra finger-typing. Since the contracts have to be spelled out.
  • Takes some amount of training to get comfortable with writing contracts.

Now, being familiar with Python primarily, I realize that it is in fact possible to write up preconditions (just throwing exceptions for inappropriate input) and it's even possible to use assertions to test again certain postconditions. But it's not possible to simulate certain features such as 'old' or 'result' without some extra magic that would ultimately be considered un-Pythonic. (In addition, there are a few libraries that offer support, but ultimately I get the vibe it would be wrong to use them, as most developers don't.) I assume that it's a similar problem for all other languages (except of course, Eiffel).

My intuition tells me that the lack of support must be a result of some kind of rejection of the practice, but searching online has not been fruitful. I'm wondering if someone can clarify why most modern languages seem to offer so little support? Is DbC flawed or overly expensive? Or is it just obsolete due to Extreme Programming and other methodologies?

share|improve this question
    
Sounds like an overly complicated way to do test-driven programming, without the benefit of also testing your program. –  Dan Jan 6 '12 at 0:06
2  
@Dan, not really, I think of it more as an extension of the type system. e.g. a function doesn't just take an integer argument, it takes an integer which is contractually obliged to be greater than zero –  Carson63000 Jan 6 '12 at 0:15
3  
@Dan code contracts significantly reduce the number of tests you need to do. –  Rei Miyasaka Jan 6 '12 at 0:32
14  
@Dan, I'd rather say that TDD is the poor-man's contracts, not vice versa. –  SK-logic Jan 6 '12 at 7:43
    
In dynamic language you can "decorate" your objects with contracts based on an optional flag. I have an example implementation which uses environmental flags to optionally monkey patch existing objects with the contracts. Yes the support is not native, but it's easy to add. The same applies to test harnesses, they are not native but they are easy to add/write. –  Raynos Jan 16 '12 at 14:02

8 Answers 8

up vote 3 down vote accepted

Arguably they are supported in virtually every programming language.

What you need are "assertions".

These are easily coded as "if" statements:

if (!assertion) then AssertionFailure();

With this, you can write contracts by placing such assertions at the top of your code for input constraints; those at the return points are output constraints. You can even add invariants throughout your code (although aren't really part of "design by contract").

So I argue they aren't widespread because programmers are too lazy to code them, not because you can't do it.

You can make these a little more efficient in most languages by defining a compile-time boolean constant "checking" and revising the statements a bit:

if (checking & !Assertion) then AssertionFailure();

If you don't like the syntax, you can resort to various language abstraction techniques such as macros.

Some modern languages give you nice syntax for this, and that's what I think you mean by "modern language support". That's support, but its pretty thin.

What most of even the modern languages don't give you is "temporal" assertions (over arbitrary previous or following states [temporal operator "eventually"], which you need if you want to write really interesting contracts. IF statements won't help you here.

share|improve this answer
    
The problem I find with only having access to asserts is that there is no effective way to check postconditions on commands since you often need to compare the postcondition state against the precondition state (Eiffel calls this 'old' and automatically passes it to the postcondition routine.) In Python, this functionality could be trivially recreated using decorators, but it comes up short when it comes time to turn assertions off. –  Ceasar Bautista Jan 16 '12 at 7:49
    
How much of the previous state does Eiffel actually save? Since it reasonably cannot know which part you might access/modify without solving the halting problem (by analyzing your function), it either has to save the complete machine state, or as a hueristic, only some very shallow part of it. I suspect the latter; and these can "simulated" by simple scalar assignments before the precondition. I'd be pleased to learn Eiffel does otherwise. –  Ira Baxter Jan 16 '12 at 8:05
4  
... just checked how Eiffel works. "old <exp>" is the value of <exp> at entry to the function, so it is doing shallow copies at function entrance as I expected. You can do them too. I'll agree having the compiler implement the syntax for pre/post/old is more convenient than doing all this by hand, but the point is one can to this by hand and it really isn't hard. We're back to lazy programmers. –  Ira Baxter Jan 16 '12 at 8:17

As you say, Design by Contract is a feature in Eiffel, which has long been one of those programming languages that is well respected in the community but which has never caught on.

DbC is not in any of the most popular languages because it is only relatively recently that the mainstream programming community has come to accept that adding constraints/expectations to their code is a "reasonable" thing to expect of programmers. It's common now for programmers to understand how valuable unit-testing is, and that percolated up to programmers being more accepting of putting in code to validate their arguments and seeing benefits. But a decade ago, probably most programmers would say "that's just extra work for stuff you know is always going to be ok."

I think that if you were to go to the average developer today and talk about post-conditions, they'd nod enthusiastically and say "OK, that's like unit-testing." And if you talk about pre-conditions, they'd say "OK, that's like parameter validation, which we don't always do, but, y'know, I guess it's ok..." And then if you talk about invariants, they'd start to say "Gee, how much overhead is this? How many more bugs are we going to catch?" etc.

So I think there's still a long way to go before DbC is very broadly adopted.

share|improve this answer
    
OTOH, the mainstream programmers had been used to writing the assertions quite for a while. The lack of a useable preprocessor in the most modern mainstream languages rendered this nice practice inefficient, but it is still common for C and C++. It is making a comeback now with the Microsoft Code Contracts (based on, AFAIK, a bytecode rewriting for the release builds). –  SK-logic Jan 6 '12 at 7:46

My intuition tells me that the lack of support must be a result of some kind of rejection of the practice,...

False.

It's a design practice. It can be embodied explicitly in code (Eiffel style) or implicitly in code (most languages) or in unit tests. The design practice exists and works well. The language support is all over the map. It is, however, present in many languages in the unit test framework.

I'm wondering if someone can clarify why most modern languages seem to offer so little support? Is DbC flawed or overly expensive?

It's expensive. And. More importantly, there are some things which cannot be proven in a given language. Loop termination, for example, cannot be proven in a programming language, it requires a "higher-order" proof capability. So so some kinds of contracts are technically inexpressible.

Or is it just obsolete due to Extreme Programming and other methodologies?

No.

We mostly use unit tests to demonstrate that DbC is fulfilled.

For Python, as you noted, the DbC goes in several places.

  1. The docstring and the docstring test results.

  2. Assertions to validate inputs and outputs.

  3. Unit tests.

Further.

You can adopt literate programming-style tools so that you write a document which includes your DbC information and which generates clean Python plus unit test scripts. The literate programming approach allows you to write a nice piece of literature which includes the contracts and the complete source.

share|improve this answer
    
You can prove trivial cases of loop termination, such as iteration over a fixed finite sequence. It's generalized looping that can't be shown to terminate trivially (since it could be searching for solutions to “interesting” mathematical conjectures); that's the whole essence of the Halting Problem. –  Donal Fellows Jan 16 '12 at 15:34
    
+1. I think you are the only one who has covered the most critical point - there are some things which cannot be proven. Formal verification may be great, but not everything is verifiable! So that feature actually restricts what programming language can actually do! –  Dipan Mehta Jan 16 '12 at 18:20
    
@DonalFellows: Since the general case can't be proven, it's hard to incorporate a bunch of features that are (a) expensive and (b) known to be incomplete. My point in this answer is that it's easier to eschew all of those features and avoid setting false expectations of formal correctness proofs in general, when there are limitations. As a design exercise (outside the language) lots of proof techniques can (and should) be used. –  S.Lott Jan 16 '12 at 20:19

Just guessing. Maybe part of the reason that it isn't so popular is becuase "Design by Contract" is trademarked by Eiffel.

share|improve this answer

One hypothesis is that for a sufficiently large complex program, especially ones with a moving target, the mass of contracts themselves can become as buggy and hard to debug, or more-so, than the program code alone. As with any pattern, there may well be a usage past diminishing returns, as well as clear advantages when used in a more targeted manner.

Another possible conclusion is that the popularity of "managed languages" is the current proof of design-by-contract support for those selected managed features (array bounds by contract, etc.)

share|improve this answer

The reason that most mainstream languages don't have DbC features in the language is the cost to benefit ratio of implementing it is to high for the language implementer.

one side of this has already been looked at in the other answers, unit tests and other runtime mechanisms (or even some compile time mechanisms with template meta programming) can give you much of the DbC goodness already. Therefore, while there is a benefit it is likely seen as quite modest.

The other side is the cost, retro fitting DbC into an existing language is likely too big a breaking change and very complex to boot. Introducing new syntax in a language without breaking old code is hard. Updating your existing standard library to use such a far reaching change would be expensive. Therefore we can conclude that implementing DbC features in an existing language has a high cost.

I'd also note that concepts which are pretty much contracts for templates, and therefore somewhat related to DbC, were dropped from the latest C++ standard as even after years of work on them it was estimated they still needed years of work. These sort of big, broad, sweeping changes to languages are just too hard to get implemented.

share|improve this answer

DbC would be used more extensively if the contracts could be checked at compile time so that it would not be possible to run a program that violated any contract.

Without compiler support, "DbC" is just anther name for "check invariants/assumptions and throw an exception if violated".

share|improve this answer
    
Doesn't that run into the halting problem? –  Ceasar Bautista Jan 16 '12 at 20:07
    
@Ceasar It depends. Some assumptions can be checked, others cannot. For example there are type systems that make it possible to avoid passing an empty list as argument, or to return one. –  Ingo Jan 16 '12 at 23:28
    
Nice point (+1) although Bertrand Meyer in his part of "Masterminds of programming" mentioned also their system of random class creation and calling checking for violation of the contracts. So it's a mixed compile time/run-time approach, but I doubt this technique works in every situation –  Maksee Apr 14 '13 at 9:40

Mostly the reasons are as follows:

  1. It's only available in languages which are not popular
  2. It's unnecessary since the same stuff can be done different way in existing programming languages by anyone who actually wants to do it
  3. It's difficult to understand and use -- it requires specialized knowledge to do it properly, so there are small number of people doing it
  4. it requires large amounts of code to do it -- programmers prefer to minimize the amount of characters they write -- if it takes long piece of code, something must be wrong with it
  5. the advantages are not there -- it just cannot find enough bugs to make it worthwhile
share|improve this answer
    
Your answer is not well argued. You are simply stating your opinion that there are no advantages, that it requires large amounts of code, and that it is unnecessary since it can be done with existing languages (the OP specifically addressed this issue!). –  Andres F. Jan 6 '12 at 2:15
    
I'm not thinking about assertions etc as a replacement for it. That's not correct way to do it in existing languages.(i.e. it wasn't addressed yet) –  tp1 Jan 6 '12 at 2:38
    
@tp1, if programmers really wanted to minimise the typing, they would never fall into something as verbose and eloquent as Java. And yes, programming itself requires "specialised knowledge" "to do it properly". Those not in possession of such a knowledge just should not be allowed to code. –  SK-logic Jan 6 '12 at 7:50
    
@Sk-logic: Well, it seems half the world is doing OO wrong simply because they don't want to write forwarding functions from member functions to the data members's member functions. It's a big problem in my experience. This is directly caused by minimizing the number of characters to write. –  tp1 Jan 7 '12 at 1:06
    
@tp1, if people really wanted to minimise the typing, they would not even touch the OO, ever. OOP is naturally eloquent, even in its best implementations, like Smalltalk. I would not say it is a bad property, eloquence helps sometimes. –  SK-logic Jan 7 '12 at 6:59

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.