Why Limited Support for Design by Contract in Modern Programming Languages?

design-by-contractlanguage-design

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?

Best Answer

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.

Related Topic