230 likes | 326 Views
Adding Contracts to Ada. Adding Design By Contract to Ada. Ehud Lamm. ADT + Contracts. type Stack is tagged private; procedure Init(S:out Stack); procedure Push(S:in out Stack; I:in Integer) at exit Size(S)=old Size(S)+1; procedure Pop(S:in out Stack;I:out Integer)
E N D
Adding Contracts to Ada Adding Design By Contract to Ada Ehud Lamm
ADT + Contracts type Stack is tagged private; procedure Init(S:out Stack); procedure Push(S:in out Stack; I:in Integer) at exit Size(S)=old Size(S)+1; procedure Pop(S:in out Stack;I:out Integer) use when not(Is_Empty(S)) at exit Size(S)=old Size(S)-1; function Size(S:Stack) return Natural; function Is_Empty(S:Stack) return Boolean; function Top(S:Stack) return Integer use when not(Is_Empty(S)); Overflow: exception; • Contracts are checked at runtime (detection). • Contract violations raise exceptions. • When possible use the type system instead (e.g., Size) • Contracts allow expressing arbitrary boollean assertions. Ada-Europe’2002
Design By Contract • Annotate each routine with axioms. • Pre-Condition & Post-Condition • (we will not talk about class invariants) • The classic ADT approach (Liskov, Guttag, Meyer) Ada-Europe’2002
Design By Contract • A contract carries mutual obligations and benefits. • The client should only call a routine when the routine’s pre-condition is respected. • The routine ensures that after completion its post-condition is respected. Ada-Europe’2002
Interface oriented programming A little polymorphic programming procedure Print_And_Empty(S: in out Stack’class) is i:Integer; begin while not(Is_Empty(S)) loop pop(S,i); put(I); end loop; end; Exercise: Prove termination for all possible stacks S. Ada-Europe’2002
Oops… type Crazy_Stack is new Stack with null record; procedure Pop(S:in out Crazy_Stack;I:out Integer) use when not(Is_Empty(Stack)) at exit (old Top(S)/=9 and then Size(S)=old Size(S)-1) or (Size(S)=old Size(S)); Does Print_And_Empty work correctly on Crazy_Stacks? Ada-Europe’2002
IS-A Otherwise bad use of public inheritance! Liskov Substitution PrincipleLSP Liskov (SIGPLAN, May 1988) Liskov, Wing (TOPLAS, Nov. 1994) Ada-Europe’2002
Why is this important? • The foundation for subtype polymorphism • Bugs surface during maintenance • Who is responsible? Ada-Europe’2002
Assigning Blame • Crucial for managing software production • Possible candidates: • The original contractor (Stack) • The polymorphic routine (Print_And_Empty) • The subcontractor (Crazy_Stack) • The user of the pm routine (should know better than to call P&E on Crazy_Stack) Ada-Europe’2002
DbC & Inheritance • Remember the LSP! • “The subclass must require less and ensure more” )Meyer, OOSC) • The only question is how to ensure this property! Ada-Europe’2002
A B DbC & LSP – more formal Assume B is derived from A, then for each method P pre(PA) → pre(PB) and post(PB) → post(PA) A B Ada-Europe’2002
The Eiffel Approach • The programmer is not allowed to make an LSP error… • require else • ensure then • A subclass can only use “or” in pre-cond / “and” in post-cond • Other tools are even worse Ada-Europe’2002
Wrong Approach • “Ensuring” correct hierarchies procedure p(T:A;I:Integer) use when i>0; procedure p(T:B;I:Integer) use when i>10; -- synthesized contract (i>0)V(i>10) • Hierarchy is malformed, language hides error. Ada-Europe’2002
Solution • Interface implied contract can be deduced from code. • Hierarchy checking is done according to run time tag of object. (Recall P&E) (more details in the paper and references) Ada-Europe’2002
P&E is responsible for Stack’s Pop pre-condition. (Stack’s pre implies actual’s pre) Actual’s Pop post-condition must be satisfied when Pop exits Actual Pop’s postcondition must imply Stack Pop post-condition Contract Checking - Analysis procedure Print_And_Empty(S: in out Stack’class) is i:Integer; begin while not(Is_Empty(S)) loop pop(S,i); put(I); end loop; end; Ada-Europe’2002
Another example: generics generic with function Sqrt(X:Float) return Float use when X>=0; procedure Print_Quad_Solutions(A,B,C:Float); -- use when B**2-4.0*A*C>=0; If actual Sqrt requires X>0, who is to be blamed when P_Q_S fails? Ada-Europe’2002
How can the language help? • Run-time enforcement • Should allow the programmer to document contracts; in a formal, standard notation • Enforce correct contract relations when possible (Hard!) • Identify faulty components and assign blame, when violations occur • When you cannot use built-in contracts: types(Think of trying to break a contract stating that the Stack contains only positive numbers) Ada-Europe’2002
Does Ada need DbC? • Ada, The Software Engineering Language • Good type system; support for generic programming • Ada interface definitions are lacking (e.g., which exceptions are raised by which routine?) • Readability and Self-Documenting code • Debugging aid • Everyone else has it (Eiffel, Java: iContract, jContractor, HandShake, JVMAssert) … • BUT: This is a major change Ada-Europe’2002
Conclusion • Perhaps still too cutting edge?! • Is there market demand? • Should we do it anyway? • Even a rudimentary implementation has important advantages. • Simpler than extending the type system • The future lies in sw components) COTS) Ada-Europe’2002
Ada needs DbC Any Questions? Ada-Europe’2002
Implementation • Can be implemented using wrapper routines • The exact wrapper routine invoked for each call is determined by relevant interface. Ada-Europe’2002
Interoperability with the old language • Old language calling new, not really an issue (but upstream contractual exceptions may be raised) • New language calling old, not really an issue (but compiler should know that a package was compiled with no contracts) Ada-Europe’2002