190 likes | 350 Views
L13: Design by Contract. Definition Reliability Correctness Pre- and post-condition Asserts and Exceptions Weak & Strong Conditions Class invariants Conditions for Class Correctness. Design by Contract. Introduced by Bertrand Meyer and supported by Eiffel. Improves reliability.
E N D
L13: Design by Contract • Definition • Reliability • Correctness • Pre- and post-condition • Asserts and Exceptions • Weak & Strong Conditions • Class invariants • Conditions for Class Correctness
Design by Contract • Introduced by Bertrand Meyer and supported by Eiffel. • Improves reliability
What is it? • Viewing the relationship between a class and its clients as a formal agreement, expressing each party’s rights and obligations!
What is Reliability? Correctness: software must perform according to its specification Robustness: software’s ability to react to cases not included in the specification
Correctness • A software system or element is neither correct nor incorrect on its own • It is correct or incorrect with respect to a certain specification
Correctness Formulae • Is an expression of the form: {P} A {Q} • Which means: • Any execution of A, starting in a state where P holds, will terminate in a state where Q holds • Eg {x>=9} x=x+5 {x>=13}
Preconditions and Postconditions • {P} and {Q} are examples of preconditions and postconditions respectively • For good programming, we need to: • document our pre- and postconditions • ensure the preconditions are true prior to executing a method • ensure the postconditions are true following method execution
How to? Two methods: • use asserts • use exceptions (L10: Exceptions)
Using assert #include <assert.h> void sort(vector<int> *vec) { // precondition assert(vec!=NULL); //... actually sort the vector // postcondition assert(is_sorted(*vec)); };
Alternative assert #include <assert.h> void sort(vector<int> *vec) { struct DBC { DBC(vector<int> *v):vec(v){ assert(vec!=NULL);}; ~DBC(){assert(is_sorted(*vec));}; vector<int> *vec; } dbc(vec); // ... actually do the sorting }
class PrecondException { PreconditionException() {} } class PostcondException { PostconditionException() {} } class Assertion { public: static void require(boolean expr) { if ( !expr ) throw PreconditionException(); } static void ensure (boolean expr) { if ( !expr ) throw PostconditionException(); } }
An Example - Stack template <class T> class Stack { private: T *data; int num_elements; int max_elements; public: Stack(int ne): max_elements(ne),num_elements(0) { data = new T[ne]; }; T pop(){...}; void push(T elem){...}; T peek(){...}; }
Push (element) • Require: stack is not full. • Ensure: stack is not empty, top = element, count++.
Pop() • Require: stack is not empty • Ensure: stack is not full, count--.
Weak and Strong Conditions • Weak conditions: • {...} A {True} // this ensures termination with a state. • {False} A {...}
Class Invariants • Are global properties of the instance of a class which must be preserved by all methods • Eg: (num_elements >= 0)&& (num_elements < data.length)
How do we Apply Them? • In general, a class invariant means that for each method: {INV && pre} body {INV && post} • So, we should check at the start and end of each method. • But, since invariants are invariant, it makes sense to bundle these checks into a method of their own.
When is a Class Correct? • A class is correct if and only if its implementation is consistent with the preconditions, postconditions and invariants.
Correctness Defined A class, C, is correct if and only if: • For any valid set of arguments, xp, to a constructor, p: {prep(xp)} Bodyp {postp(xp) && INV} • For every public method, r, and any set of valid arguments, xr: {prer(xr) && INV} Bodyr { postr(xr) && INV}