22
Adding Contracts to Ada Ehud Lamm Adding Design By Contract to Ada

Adding Contracts to Ada Ehud Lamm Adding Design By Contract to Ada

  • View
    215

  • Download
    0

Embed Size (px)

Citation preview

Adding Contracts to Ada

Ehud Lamm

Adding

Design By Contract

to Ada

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’200220

Ada needs DbC

Any Questions?

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.

19.7.2002 Ada-Europe’200222

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)