Download 22-validation-designbycontract_ppt [Compatibility Mode]

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
Transcript
Software validation:
Design by Contract
Defensive Programming
A dynamic technique: Detect failures
Defensive Programming
•
Assertions
•
if (age<=0) then /* handle error */ else i = 1/age;
public void method(Object arg) { if arg==null …}
Provide appropriate exception handlers
Invariants
•
Example:
Pre-/postconditions
•
Incorporate checks wherever possible
In object-oriented programming: Design by Contract (B.
Meyer, 1985)
CE202 & CE654 Software Engineering, Spring term 2010–11
1
Dr Amnon H. Eden, School of Computer Science and Electronic Engineering, University of Essex
Objects as Service Suppliers
“Contract”
Communicating objects take two roles:
2
The purpose of the contract is
Supplier
Client
double sqrt(double arg) {
// arg >= 0
// ...
// Calculate & return square root of sqrt
// |result*result–arg| < 0.001
}
How this differs from documentation?
Contract
3
To render the agreement explicit
To avoid “misunderstandings”
To trace pinpoint (clarify) violations of the agreement
Cannot be checked mechanically
Inconsistent with the code
Usually ignored
4
1
Structure of a Contract
Two sides to a contract:
Example: Square Root
double sqrt(double arg) {
// ...
// Calculate & return square root of sqrt
}
The Client: The necessary
obligations so that the operation can
be carried out
The commitments are:
The Supplier: What can be
promised as an outcome (given the
obligation of the customer)
6
Exercise
Write a precondition for sqrt
Write a postcondition for sqrt
Hint:
A pre/postcondition can be simulated using if statements
arg >= 0
From the supplier’s side: |result2-arg| < ε
The supplier’s part is a
postconodition
5
From the client’s side:
The client’s part is
a precondition
Pre- and Post-conditions
Precondition: The client’s side of the contract
Postcondition: The supplier’s side of the contract
Because the client’s part is a condition on the arguments to
the operation
Because the supplier’s part is a condition on the result of the
operation
double sqrt(double arg) throws OutOfBounds, CalcError {
if (arg < 0)
// Simulate precondition
throw OutOfBounds;
double result;
// ... Calculate square root of arg
if (result*result–arg > 0.001 || // Simulate postcondition
result*result–arg < -0.001)
throw CalcError;
return result;
}
7
8
2
Using assertions in Java
Assertions in Java
SQRT example:
double sqrt(double arg) {
assert arg <= 0 : "arg is negative"; // Simulate precondition
double result;
// ... Calculate square root of arg
assert result*result–arg < 0.001 || // Simulate postcondition
result*result–arg > -0.001;
return result;
}
By default: Assertions are disabled in run time
To enable: Use run-time switches
%java -enableassertions CalculateFactorial
%java –enableassertions:pkg CalculateFactorial
Compiling with assertions
%javac -source 1.4 CalculateFactorial
9
10
Reminder: Stack
Example: Stack pre- and postconditions
stack.pop()
Data structure: LIFO (Last In First Out)
public class Stack {
public void push(Object x); // Add x to top
public Object pop();
// Remove and return top
public Object top();
// Return top
public boolean empty();
// Return true iff empty
public int size();
// Return size
}
Precondition: not empty()
Postcondition: (old size) = (size + 1)
stack.push(Object x)
Precondition: x != NULL
Postconditions:
push(3);
push(2);
3
Empty==true
11
Empty==false
not empty
old size = size – 1
top() == x
pop();
2
3
3
s.pop() == 2
12
3
Examples (Cont.)
Calculate n! (factorial n), defined:
factorial(n) == 1*2*3*…*n
Factorial (Cont.)
Implementation #1: the recursive version
Precondition: n >= 1
public int factorial(int n) {
if (n == 1) return 1;
return n * factorial(n-1);
}
Consider this implementation:
public int factorial(int n) throws OutOfBounds {
if (n <= 0)
throw OutOfBounds;
// A precondition?
if (n == 1)
return 1;
return n * factorial(n-1);
}
How can we write a precondition in Java?
13
What is wrong with this solution?
The condition will be tested n times, but it should only be
tested once!
14
Factorial (Cont.)
Factorial (Cont.)
Alternative #1: Use a while loop
public int factorial(int n) throws OutOfBounds {
if (n < 1)
throw OutOfBounds;
// A precondition?
i = 0;
result = 1;
while (i <= n) {
i = i + 1;
result = result * i;
}
}
15
Alternative #2: Use a nested method
public int factorial(int n) throws OutOfBounds {
if (n < 1)
throw OutOfBounds;
// A precondition (?)
return factorial_untested(n);
}
private int factorial_untested(int n) {
// Not a public method: no need for precondition
if (n == 1)
return 1;
return n * factorial_untested(n-1);
}
16
4
Factorial (Cont.)
Assertions
Alternative #3: Use Eiffel
“Sanity checks”: Test that “all is well”
factorial(integer: i): integer
require -- Precondition
not i <= 0;
is // { In Java
if i = 1 Result := 1
else Result := n*factorial(n-1);
ensure -- Postcondition
Result*Result <= 0.001 and Result*Result >= -0.001;
end; -- Factorial
public int factorial(int n) {
if (n == 1)
return 1;
int fac = factorial(n-1);
assert fac > n-1 || n == 2;
return n * fac;
}
// Sanity check
...
17
18
Invariants
Invariant: A condition that must always be met
In code: A condition over the integrity of the program at a certain point in the
control flow
»
Design By Contract in Eiffel
deferred class TREE[G]
-- ...
is_leaf: boolean;
arity: integer;
int k;
// ...
assert k != 0;
int l = i/k;
require -- Precondition
not is_root
is_leaf(t) if-and-only-if arity=0
»
Size() >= 0
Empty() == (Size() == 0)
ensure -- Postcondition
is_sibling (Result);
(Result/=Void) implies Result.right_sibling=Current);
Class stack:
»
19
deferred -- an abstract routine
Class tree:
»
-- Number of children
left_sibling: like parent is –- Return left neighbor (if any)
Class Invariant: is a condition that holds at exit of every public method.
-- abstract class
end; -- left_sibling
-- ...
invariant
is_leaf = (arity = 0);
child_islast = (not is_leaf and child_index = arity);
end -- class TREE
20
5
Would these work in Java?
public class TREE
public TREE left_sibling() {
TREE Result;
... // Calculate Result
assert if (Result != null) // Postcondition
Result.right_sibling() == this;
public TREE right_sibling() {
TREE Result;
... // Calculate Result
assert if (Result != null) // Postcondition
Result.left_sibling() == this;
}
Invariants in Java
Invariants are not directly supported
Instead: Use assertions at end of public methods
public class Stack {
public Stack() {
assert CheckInvariants();
}
public void push(int arg) {
... // Push implementation
assert CheckInvariants();
}
...
private boolean CheckInvariants() {
return Empty() == (Size() == 0);
}
}
public abstract class Collection
abstract int size() {
assert (Result >= 0) // Postcondition
}
22
Invariants in Eiffel
Exercise
deferred class Stack -- Abstract class
Write class invariants for class date
Size(): int is ... -- method definition here
Empty(): boolean is ... --method definition here
-- remaining class definition here
invariant
Empty() == (Size() == 0);
end -- class Stack
23
public class Date
private int day month year;
...
public bool is_later_than(Date other)...
public bool is_earlier_than(Date other)...
public add(int no_days) { // calculate new date
// precondition?
// postcondition?
}
24
6
Exercise
Offer preconditions for PhoneCall.length()
Offer an invariant for class PhoneCall
public class PhoneCall{
private TimeAndDate
start, // defined when connection established
end;
// defined when connection terminates
private boolean connectionEstablished;
private boolean active; // True if call started but not terminated yet
public TimeInterval length() {
return end – start;
}
...
}
25
7