Design by Contract in Eiffel 2002/04/15 ctchen@canthink.com.com.tw.tw
Reference & Resource Bertrand Meyer, Object-Oriented Oriented Software Construction 2nd,, 1997, PH. Bertrand Meyer, Eiffel: The Language,, 1992, PH. D. Mandrioli and B. Meyer, A Advances in Object- Oriented Software Engineering,, 1992, PH. JM. Jezequel et, al., Design Patterns and Contracts, 1999, AW. R. Mitchell et, al., Design by Contract, by Example, 20002, AW. http://www.eiffel.eiffel.com..com. http://java.sun.com/j2se/1.4/docs/guide/lang /lang/asser/asser t.html.
Outline Introduction to Design by Contract Why Design by Contract? The Eiffel language. What is a Contract? Exception Handling. Inheritance. Documentation. Contracts in Analysis. Conclusion. Q&A.
Why Design by Contract?
How to Build Reliable OO Software? We need: Static typing. Garbage collection. Reusability libraries. This is not enough, we also need: A systematic approach to specifying and implementing OO software elements and their relations. Such a method Design by Contract: A software system is viewed as a set of communicating components whose interaction is based on precisely defined specifications of the contracts.
Reliability in Eiffel Correctness: Assertion. Robustness: Exception handling.
Partial functions (1/2) Some operations are not applicable to every possible element of their source sets: In class Stack, method pop and top- cannot pop an element from an empty stack; and an empty stack has no top. inv (x) = 1 / x. A function from a source set X to a target set Y is partial if it is not defined for all members of X. A function which is not partial is total.
Partial functions (2/2) Partial functions are an inescapable fact of software development life: Not every operation is applicable to every object. A potential source of errors: If f is a partial function from X to Y, we are not sure any more that the expression f (e) makes sense. Partial functions must specify the domain of each of them. This is the role of the precondition.
Correctness formula Axiomatic semantics: Floyd, Hoare and Dijkstra. {P} A {Q} Any execution of A, starting in a state where P holds, will terminate in a state where Q holds.
Class correctness For creation procedure p: {pre p } Body p {post p and INV} For exported routine r: {pre r and INV} Body r {post r and INV} For rescue clause in routine r: {True} Rescue r {INV} For retry clause in routine r: {True} Retry r {INV and pre r }
The Eiffel Language
Some language features (1/2) Pure object-oriented oriented language. Garbage collection. Consistent type system. Static typing. Classes as the basic structuring tool. Design by Contract. Assertions. Exception handling: rescue & retry. Multiple inheritance. Feature renaming. Redefinition & Explicit redefinition.
Some language features (2/2) Deferred features and classes. Subcontracting. Generic Type: Unconstrained & Constrained. Once routines. External interfaces. Self-documentation. No in-class overloading. No global variables. No goto instructions. No low-level level pointers, no pointer arithmetic.
Hello World in Eiffel
What is a Contract?
Fundamental properties of contracts in human affairs A contract implies obligations and benefits for both parties. An obligation for one maps into a benefit for the other. The obligations and benefits are explicit: : the role of the contract document is precisely to spell them out in detail, avoiding ambiguity inasmuch as humanly feasible. Some general clauses may remain implicit because they automatically apply to all contracts. An obligation is actually also a benefit for the corresponding party.
Assertions: Contracting for Software Producing correct and robust software: To make explicit the obligations and guarantees on any call. The mechanisms are called assertions. Contracts: A collection of assertions that describe precisely what each feature of the component does and does not do. In Eiffel: Precondition require (require else). Postcondition ensure (ensure then). Invariant - invariant.
Contract put an item into a table Obligations Benefits Client (Must ensure precondition) Make sure table is not full and key is a non-empty string. (May benefit from postcondition) Get updated table where the given element now appears, associated with the given key. Supplier (Must ensure postcondition) Record given element in table, associated with given key. (May assume precondition) No need to do anything if table is full, or key is empty string.
Generic Class DICTIONARY [ELEMENT] precondition postcondition
Writing down the contract Contract document should spelled out precisely. Contract protects both sides: It protects the client by specifying how much should be done: the client is entitled to receive a certain result. It protects the contractor by specifying how little is acceptable: the contractor must not be liable for failing to carry out tasks outside of the specified scope.
Observations on software contracts (1/3) if count < capacity then Some insertion algorithm else end Deal with normal case Rule: Either you have the condition in the require, or you have it in an if instruction in the body of the routine, but never in both. Preconditions are sometimes viewed with suspicion shouldn t t a routine be prepared to handle all possible inputs?
Observations on software contracts (2/3) It should not: The stronger the precondition, the higher the burden on the client, and the easier for the contractor. The matter of who should deal with abnormal values is essentially a pragmatic decision about division of labor : the best solution is the one that achieves the simples architecture.
Observations on software contracts (3/3) Bad cases: Every routine checked for every possible error in its calls no useful work would ever be performed. Both the client and the routine check for the same conditions - redundancy. A good case: Routines with strong preconditions will concentrate on performing well a precisely defined task, rather than attempt to handle all possible abnormal cases.
Who should check (1/4) tolerant weak Increasing the routine s burden precondition demanding strong Putting the responsibility on clients The key criterion: To maximize the overall simplicity of the architecture. The Eiffel is on the demanding side: it encourages writing simple routines with a well-defined contract rather than routines which will attempt to handle every imaginable case.
Who should check (2/4) Question? /A/ if x.p then x.r else end The demanding style seems to force every client to make the same checks, corresponding to the precondition. ex: precondition p in a routine r: Special treatment
Who should check (3/4) Precondition means : x.put; x.remove; The client must guarantee property p, which is not the same as testing for this condition before each call.
Who should check (4/4) Assume many clients will indeed need to check for the precondition, as in form /A/ above. What matters then is the Special treatment in the else clause? It may be the same for all calls. This is almost certainly a sign of a poor contract for the routine r. If there is a well-defined standard action for the case not p, the the routine s s precondition as given is too restrictive. The Special treatment being moved from the individual clients to the routine itself. If it is different for various clients, the individual test for p by every client is inevitable. Each has defined its own way of dealing with the case for which p is not satisfied (occurs frequently- only the clients have enough context information to decide on the proper action).
Monitoring assertions Assertion monitoring levels in Efiiel: No assertion checking at all. Preconditions only (default). Preconditions and postconditions. Preconditions, postconditions, invariants. The effect of an assertion violation is to raise an exception.
Exception Handling
What is an Exception? Any routine has a contract to achieve. Its body defines a strategy to achieve it a sequence of operations. Any one of these operations may fail unable to meet its contract. The failure of an operation is an exception for the routine that needed the operation. As a result the routine may fail too causing an exception in its own caller.
Failures and Exceptions A failure of a routine causes an exception in its caller my_task is do subtask 1 ; subtask 2 ; subtask n ; end -- my_task If any one of subtasks fail, it must causes an exception to its caller, that is my_task.
How to Handle Exceptions?
Retry many times
Disciplined Exception Handling principle R1- Retrying: attempt to change the conditions that led to the exception and to execute the routine again from the start. R2- Failure (organized panic): clean up the environment, terminate the call and report failure to the caller.
Inheritance
Example class COURIER
Obligations and Benefits for Clients and Suppliers
class DIFFERENT_COURIER
Redefining Contracts Redefining a Precondition: Weight of package must not exceed 8 kg OK (less restrictive). Weight of package must not exceed 3 kg No good (more restrictive). Redefining a Postcondition: Package delivered within 2 working hours. OK (more restrictive). Package delivered within 5 working hours. No good (less restrictive).
Principle of Subcontracting A redefined version may keep or weaken the precondition; it may keep or strengthen the postcondition: Require no more, promise no less. Dishonest subcontracting: Strengthening the precondition, or weakening the postcondition The Eiffel language rules for assertion redefinition support the principle of subcontracting. The Liskov Substitution Principle.
require else & ensure then
require else in subclasses
ensure then in subclasses
Another Example
The Error Message ISE EiffelStudio 5.1.14
invariant in subclasses A subclass inherits its superclass s invariant. It can add more clauses to the invariant, which are and-ed onto the inherited clauses, thus strengthening the inherited invariant.
Inheritance Not just a reuse, subtyping and classification mechanism, but a way to ensure compatible semantics. Contracts provide useful guidance as to how to use inheritance properly.
Documentation
Different View of a Class 1. Clickable view. 2. Flat view. 3. Contract view. 4. Interface view. 5. Ancestors. 6. Descendants. 7. Clients. 8. Suppliers. 9. Attributes. 10. Routines. 11. Deferred features. 12. Once routines and constants. 13. External features. 14. Exported features.
Contracts in Analysis
Contracts in Analysis Example : feature of class TANK Yes/no queries: is_empty, is_full... Other queries: in_valve, out_valve (both of type VALVE), gauge_reading, capacity... Commands: fill, empty,...
Contracts in Analysis (cont.)
Contracts in Analysis (cont.) This style of analysis avoids a classic dilemma of analysis and specification: either you use a programming notation and run the risk of making premature implementation commitments; or you stick with a higher-level notation ("bubbles and arrows") and you must remain vague, forsaking one of the major benefit of the analysis process, the ability to state and clarify delicate properties of the system.
Conclusion (1/4) Eiffel is a method and language for efficient description and development of quality systems. Eiffel covers whole spectrum of software development: Analysis, modeling and specification. Design and architecture. Implementation. Debugging and Testing. Maintenance. Documentation.
Conclusion (2/4) Contracts: Are not a mechanism to test for special conditions, for example erroneous user input. An assertion is instead a correctness condition governing the relationship between two software modules Not a software module and a human, or a software module and an external device. Assertion violation rule: A precondition violation signals a bug in the client,, which did not observe its part of the deal. A postcondition (or invariant) violation signals a bug in the supplier which did not do its job.
Conclusion (3/4) Benefits of Design by Contract: Better designs. Improving reliability. Better documentation. Easier debugging. Support for reuse.
Conclusion (4/4) Lack of language support: Eiffel is the first language directly support for design by contract. Java JDK 1.4 now support assertions: New keyword - assert. New class AssertionError. No directly support for design by contract. See: http://java.sun.com/j2se/1.4/docs/guide/lang /lang/assert.html/assert.html How about tools like icontract?
Q & A