adding contracts to ada ehud lamm adding design by contract to ada
Post on 22-Dec-2015
215 views
TRANSCRIPT
19.7.2002 Ada-Europe’20022
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;
1. Contracts are checked at runtime (detection).
2. Contract violations raise exceptions.
3. When possible use the type system instead (e.g., Size)
4. Contracts allow expressing arbitrary boollean assertions.
19.7.2002 Ada-Europe’20023
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)
19.7.2002 Ada-Europe’20024
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.
19.7.2002 Ada-Europe’20025
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;
Interface oriented
programming
Exercise: Prove termination for all possible stacks S.
19.7.2002 Ada-Europe’20026
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?
19.7.2002 Ada-Europe’20027
Liskov Substitution PrincipleLSP
Liskov, Wing (TOPLAS, Nov. 1994)
Liskov (SIGPLAN, May 1988)
Otherwise bad use of public inheritance!
19.7.2002 Ada-Europe’20028
Why is this important?
• The foundation for subtype polymorphism
• Bugs surface during maintenance
• Who is responsible?
19.7.2002 Ada-Europe’20029
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)
19.7.2002 Ada-Europe’200210
DbC & Inheritance
• Remember the LSP!
• “The subclass must require less and ensure more” )Meyer, OOSC)
• The only question is how to ensure this property!
19.7.2002 Ada-Europe’200211
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
A
B
19.7.2002 Ada-Europe’200212
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
19.7.2002 Ada-Europe’200213
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.
19.7.2002 Ada-Europe’200214
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)
19.7.2002 Ada-Europe’200215
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;
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 post condition must imply Stack Pop post-condition
19.7.2002 Ada-Europe’200216
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?
19.7.2002 Ada-Europe’200217
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)
19.7.2002 Ada-Europe’200218
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
19.7.2002 Ada-Europe’200219
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)
19.7.2002 Ada-Europe’200221
Implementation
• Can be implemented using wrapper routines
• The exact wrapper routine invoked for each call is determined by relevant interface.