A survey of the 'Design by Contract' paradigm S V Ramu (2002-07-27) Prelude
In continuing the language survey, that started with
Python,
to understand the role and limitations of
a programming language in coloring our ideas and in producing reliable
software, I stumbled upon
Eiffel
and its motto of Design by Contract
(the superset of the Reuse and 'Design by Contract'
The Holy Grail of all software effort is Reuse. None of us, who take pride in what we do, would like to recreate again and again what we have done well already. Like all other creative fields like Science, Music, Art, Films etc., in software too, building upon old achievements is a sacred act. Unfortunately one big impediment in achieving this is that the requirements are changing continuously, and a piece of code written for one purpose rarely fits a new one. And with the notorious Reuse error of the much touted Ariane spacecraft debacle, one is in fact very hesitant to reuse something on its face value. The article says,
A recent $500 million software error provides a sobering reminder that this
principle is not just a pleasant academic ideal. On June 4, 1996, the maiden flight
of the European Ariane 5 launcher crashed, about 40 seconds after takeoff. Media
reports indicated that a half-billion dollars was lost - the rocket was uninsured.
Particularly vexing is the realization that the error came from a piece of the software that was not needed. The software involved is part of the Inertial Reference System, for which we will keep the acronym SRI used in the report,... The exception was due to a floating point error during a conversion from a 64-bit floating-point value, representing the flight's "horizontal bias," to a 16-bit signed integer... What was truly unacceptable in this case was the absence of any kind of precise specification associated with this reusable module. The requirement that the horizontal bias should fit on 16 bits was in fact stated in an obscure part of a mission document. But it was nowhere to be found in the code itself! There is a more simple lesson to be learned from this unfortunate event: Reuse without a precise, rigorous specification mechanism is a risk of potentially disastrous proportions. By the way, it would interest you to know, as found in the elaborate and useful article, Why Eiffel by Todd Plessel,
Standard Ada 95 does not include the 'Anna' assertions package. This prevents
Design by Contract and its benefits in program documentation and reliability.
(This has been cited as a cause of a recent failed rocket launch.)
What is 'Design by Contract'? What is Eiffel?
In many ways the principle of Design by Contarct (Trademark of Eiffel Software Inc.), and Eiffel, the language that first introduced it, cannot be explained without references to each other and of course to it illustrious creator, Bertrand Meyer. The language gets its name, inspired from the legendary Gustave Eiffel (1832--1923) of France, who built the The Eiffel Tower, ... in 1887 for the 1889 World Fair, was completed on time and within budget...
In his article, Eiffel's Design by Contract, Mayer quotes an accolade from McKim, which gives a concise history of this 'Design by Contract' concept.
The concepts of preconditions and postconditions to form a contract on a routine
go back at least to Dijkstra and Hoare in the late 60's and early 70's. In the
late 70's and early 80's there were a couple of experimental languages Alphard and
Euclid that were designed to support assertions. It's not clear to me how much
they succeeded in implementing these, however. --McKim
A comparison article by Bertrand Meyer, Eiffel vs C++, gives a simple and vivid definition of the Design by Contract principle. And for more information on this principle, you can check out their DBC related web page.
A fundamental property of Eiffel software is that it may be equipped with
assertions. Assertions are elements of formal specification that serve to
characterize the semantics of classes and their routines independently of their
implementation. Assertions include in particular routine preconditions (which must
be satisfied when a routine is called), routine postconditions (ensured by the
routine on exit) and class invariants (global consistency conditions applying to
every instance of a class).
Assertions are essential for documenting components. As a matter of fact, I do not understand how one can talk about the very idea of reusable software components without assertions. Using a hardware analogy, a software component without assertions is similar to, say, an amplifier without precondition (the acceptable input voltage), postcondition (the gain, expressed as acceptable ratio of output to input) and invariant (including for example the temperature limits expected and maintained by the amplifier). Yet of widely available programming languages, only Eiffel has these notions. To quote the quote from the article Java and 'Design by Contract' by Geoff Eldridge,
Part of the liberation of working in DbC fashion derives from the
absolute guarantee that the entire system plays by the rules; the
freedom *not* to play by the rules breaks the (as it were)
meta-contract that makes Eiffel Eiffel. -- Tim Peters, 21 Nov 98
A good quote to explain the motive of the Eiffel language, would be the very quote of the site's eloquent and to-the-point, introductory article, Eiffel in a Nutshell. This also gives a wonderfully concise example for exhibiting a reusable class (a numeric counter), with reasons for using the DBC features.
As Roland Racko wrote in Software Development: "Everything about Eiffel is
single-mindedly, unambiguously, gloriously focused on reusability -- right down
to the choice of reserved words and punctuation and right up to the compile time
environment". We couldn't say it better. Eiffel was designed from day one to be
the vehicle for the new software industry, based on the reuse of high-quality
components -- rather than on everyone reinventing the wheel all the time.
Eiffel: A short overview
To be frank, after seeing Eiffel and its much hyped DBC, I did (and do) feel a bit like switching to it! Of course the regulation fear of not being in the popularly supported platform, does threaten me. In fact, it would be nice if there is a language that has Python like indentation based syntax, with Eiffel like DBC features, Perl like natural Regular expressions, and Java like mass support. Anyway, it might be still too premature for me, to have a concrete wish list for a language, other than some spur-of-the-moment frustrations. If not anything, knowing a new language does expand your depth of usage in the known one. In that vein let us learn Eiffel. Do remember, this is only a personal comparative crash course of the Eiffel language. You can check the following links for more information.
At the first sight, the Eiffel tokens (syntax units) has an
Object Pascal (Borland Delphi) feel
to it. Especially its departure from C/Java model of denoting equality and
assignment. Eiffel uses
Not only these basic operators, even the keywords of the language have the
distinct 'wordy' feel of Pascal, especially the
class HELLO_WORLD
In Eiffel, a line starting with two hyphens is a comment (like in HTML etc).
Also note that Eiffel users keep their class name in caps (!); constants are
plain variables here. the While reading this article, I was surprised of the so many outdated comments about C++, like, C++ not having templates and multiple inheritance! Only then did I realize that this article was written in 1989, and even then Eiffel had the features like safe Multiple Inheritance (now unanimously condemned and replaced by Interfaces), genericity (now the template classes of C++, and which is slated for adoption in J2SE 1.5 tiger release), Exceptions (which I thought was there from early C++ days), Deferred classes (it is amazing that C++ got Abstract classes only after 1989), and of course the glorious type unification (which is ridiculed for partial implementation in .NET and safe removal from Java with wrapper classes). It was illuminating to note that Eiffel had one primitive class called BITS M for creating INTEGER, REAL etc. as Classes, without performance sacrifice. I envy this feature. The simple and powerful example given in the introductory Eiffel in a Nutshell article, would be the best way to illustrate the reusability focus, and the syntactic structure of the Design by Contract model of writing code. The following code is as in the site, with some reduction of white spaces, to highlight the simple structure for appreciation. I'll repeat the Mayer's words on this DBC notion again, for emphasis.
A fundamental property of Eiffel software is that it may be equipped with
assertions. Assertions are elements of formal specification that serve to
characterize the semantics of classes and their routines independently of their
implementation. Assertions include in particular routine preconditions (which must
be satisfied when a routine is called), routine postconditions (ensured by the
routine on exit) and class invariants (global consistency conditions applying to
every instance of a class).
class COUNTER
Note the keywords DBC and Java
Bertrand Mayer strongly criticizes all the major modern paradigms of reusability, like ActiveX, JavaBeans, CORBA IDL, since they don't incorporate contract (and hence reliability of reuse) into it. In his forceful article Avoiding the Second Historic Mistake he argues that Java is committing some of the very same mistakes that caused the dethroning of C++ from its heights. Yet, he also goes on to accept this plurality of languages, and even hints about the need for C++ wrappers and Java Byte code generators for Eiffel (This was in 1997. These tools are currently available even with the free SmallEiffel implementation).
But the forced march to Java in 1997 is no more justified than the mass
conversions to C++ in 1987. This time we don't have the excuse that we
don't know; and no spacecraft hides, ready to rescue us, behind the comet.
... Can we as an industry learn from our mistakes? How many more Taligent-like
catastrophes are needed, with Java replacing C++, to discover the obvious?
Must we lose another ten years?
Nevertheless, the 'once' Java lover in me, did urge me to look around for the DBC
like functionality in Java. Of course many of you might now be using the
J2SE 1.4 feature of Thanks to the nice wrapper article Java and 'Design by Contract' by Geoff Eldridge, we are led to a surprising fact that James Gosling had indeed designed assertion in his Oak 0.2 specification (section 7.1 and 7.2), as a part of the Green project (the java precursor). Except for class invariants of Eiffel, he has included both pre and post condition, and even a SQL constraints like variable level assert. Unfortunately, it seems he has ripped of these parts due to time constraint of the project. By the way, a simple tool called iContract, is trying to emulate the DBC functionality through a java preprocessor using special javadoc tags (@pre, @post etc). Notably the JASS - Java with assertions project is trying to bridge the gap for the time being, by providing all of the DBC features through preprocessing of special java comments (the ** variety). Changes in J2SE 1.4
Assertion Facility in java is simple but looks strong.
assert Expression1;
assert Expression1 : Expression2 ; In both forms of the assert statement, Expression1 must have type boolean or a compile-time error occurs. If assertions are disabled in a class, the assert statements contained in that class have no effect. If assertions are enabled, the first expression is evaluated. If it evaluates to false, an AssertionError is thrown.
If the assertion contains a second expression (preceded by a colon),
this expression is evaluated and passed to the constructor of the
AssertionError; otherwise the parameterless constructor is used. (If the first
expression evaluates to true, the second expression is not evaluated).
If an exception is thrown while either expression is being evaluated, the assert
statement completes abruptly, throwing this exception.
This is almost everything of what Java has to offer for DBC; and remarkably this is lot, though not everything. A typical usage scenario could be,
int convertSuit( int suit) {
The simple assertion facility does enable a limited form of design-by-contract
style programming. The assert statement is appropriate for postcondition and
class invariant checking. Precondition checking should still be performed by
checks inside methods that result in particular, documented exceptions, such as
IllegalArgumentException and IllegalStateException.
Class invariants needs an internal
method to be used by the assertion in appropriate places (Eiffel's is simpler).
The major drawback is, these asserts are not
inherited by the sub classes, unless the super class method itself is called.
This is what could be changed by introducing full blown DBC. Notably,
the usage guideline says that public method's precondition (
We considered providing such a (full DBC like) facility, but were unable to convince
ourselves that it is possible to graft it onto the Java programming language without
massive changes to the Java platform libraries, and massive inconsistencies between
old and new libraries. Further, we were not convinced that such a facility would
preserve the simplicity that is Java's hallmark. On balance, we came to the
conclusion that a simple boolean assertion facility was a fairly straight-forward
solution and far less risky. It's worth noting that adding a boolean assertion
facility to the language doesn't preclude adding a full-fledged design-by-contract
facility at some time in the future.
Epilogue
There is no denying fact that Eiffel is by far a superior design, especially considering that it is there from 1985 (java is 1995+). But Java is fast growing. Though a language cannot grow beyond its basic premise and restrictions, there is still lot of scope for java. With all the abuse that is showered on Java (due to its popularity), once the Generics comes into the language (now that assertion is already there), almost 80% of all idealistic concepts of a OOP will be there in it. Yes, still there are many minor grievances towards java (like, lack of type unification, interpretive runtime, no multiple inheritance, enum dilemma etc.), but these are largely controversial and can be forgiven, given its relatively simple linguistic structure, unparalleled ubiquity and of course the extensive and collaborative APIs. To conclude, I concur with the broad view of Ian Joyner in his article, C++?? : A Critique of C++ (3rd Ed.). Though that article's sole purpose is to lash out on C++ (rightfully so), it does expound many a general truth worth pondering. Beyond a point, we will have to grow out of being habituated to thinking through a language, to thinking through sound Software Engineering principles. Remember, the great C was dethroned, the invincible C++ went away, even the now hot Java has to succumb to its design limitation some day, but programming will still be around (maybe fully changed) in some form or the other. Only the general principles of modularity and simplicity can be ever with you.
A programming language is just a tool, in the same way that an axe is a tool.
If the axe is blunt when chopping down a tree, then procedures, processes and
methodologies could be invented to make it as effective as possible; but that
leaves the real problem unsolved: that the axe that does the real work is blunt.
...A poor axeman could be ineffective with even a sharp axe, but the axe maker
will still strive to produce the sharpest axe for the good axeman. The argument
that poor programmers will produce bad programs in any language so we shouldn't
bother with better languages is fallacious.
Java is still an unproven entity for large projects (in 1996), and the byte code is interpreted. Eiffel and C++ are roughly equivalent in performance. Interpreted Java will be around 10 times slower. But Java byte codes could be compiled into native code. In a nutshell, an object-oriented language that lacks the qualities of a high level language entirely misses the point of why we have progressed from machine coding to symbolic assembler and beyond. Without the essential high level qualities, OO is nothing but hype. Eiffel shows that it is important to be high level as well as OO, and I hope that the lesson to be learned by any programming paradigm, not just OO, is that the fundamental is to make the task of programming (that is system development as a whole) easier by the removal of the burden of bookkeeping. My hope is that the industry establishes a professional software engineering culture, not a programming language culture based on seriously flawed and arcane languages. The software engineering culture is not well represented in C++. - Ian Joyner - October 1996 |