1.44k likes | 1.46k Views
Learn about the importance of assertions for formal correctness, testing, and documentation in programming. Explore compile-time versus runtime properties and application-independent assertions.
E N D
Assertions Prasun Dewan Comp 114
Assertions • Declare some property of the program • Used for • formal correctness • testing • documentation • specification
Compile time vs. runtime properties • Some assertions language supported • Compile time • String s = nextElement() • Runtime • ((String) nextElement()) • Asserting type properties of object. • Assertions describe runtime properties
Application-independent vs. dependent • Language can provide us with fixed number of application-independent assertions. • Cannot handle • First character of String is a letter. • Letter concept not burnt into language. • Class Character defines it • Innumerable assertions about letters possible • Second elements of string is letter. • Third element of string is letter. • Need mechanism to express arbitrary assertions
Assertions vs. Exceptions • Wrong assertion results in exception. • Wrong class cast leads to class cast exception.
Reasons for exceptions • User error • Programmer cannot prevent it • Internal error • Programmer can prevent • Assertions catch internal errors.
Reasons for assertions • Why catch internal errors via assertions? • Alternative: Make test runs and look at output.
Finite test runs • Some errors not exhibited in test runs. • Inconsistent string not printed because of user option.
Late detection • Output produced much after the cause • Storing an inconsistent string causes erroneous output when the string is matched not when it is stored.
Complex output • May not know what the output is, but know the relationship between input and output • (123.345 * 789.123 ) 123.345 == 789.123 • Number is divisible by a prime factor
No manifestation in output • Some errors have to do with efficiency. • Storing duplicate items in a set. • Not exhibited in output
Example Assertion { y = 10/x; z = 5} assert (y == 10/x) & (z == 5)
Definition • Example { y = 10/x; z = 5} assert (y == 10/x) & (z == 5) • Statement regarding • State of program (variable values) • Program counter (currently executing statement) • PC implicit by putting assertion next to a statement • Specifies Boolean expression involving selected program variables • Assertion fails if boolean expression false • Not all program variables named • X unnamed above • Does not care about unnamed variables
Role of Assertions • Debugging • Exception thrown if assertion fails • Documentation // detailed prime factor computation code …. assert (number % prime) == 0 • Specification • Assertion defined desired result of the code to be implemented • Formal correctness • Can prove if assertion met by code. • Need assertions regarding language constructs
Recording Variables • Cannot say: {X = X + 1} assert X == X + 1; • Introduce recording variable {oldX = X; X = X + 1} assert X = oldX + 1 • Special variables needed to make assertions sometimes
assert (x !=0) { y = 10/x; z = 5} assert (y == 10/x) & (z == 5) Precondition What is expected before statement(block) execution Postcondition What is guaranteed after statement(block) if precondition met Together define a contract Preconditions and Postconditions
pre (x !=0) post (y == 10/x) & (z == 5) { y = 10/x; z = 5} Both conditions placed before statement block. Alternative syntax
x = 0; pre (x !=0) post (y == 10/x) & (z == 5) { y = 10/x; z = 5} Precondition may not be satisfied by previous incorrect statement. Yet it is a correct precondition Incorrect precondition?
pre (x > 0) post (y == 10/x) & (z == 5) { y = 10/x; z = 5} Some assertions imply others x > 0 x !=0 Implied assertion is considered weaker. Can always replace precondition with a stronger one. Prefer weakest precondition Requires fewest assumptions. Statement can be used in more contexts Better documentation Alternative precondition
pre (x != 0) post (z == 5) { y = 10/x; z = 5} Some assertions imply others y == 10/x & (z == 5) => z == 5 Can always replace postcondition with a weaker one Prefer strongest postcondition More detailed documentation Can be used in more contexts Can be followed by statements with stronger preconditions. Alternative postcondition
Course Analogy • Preconditions • Declared course prerequisite • Post conditions • Advertised objectives • Stronger precondition • Does not allow some students to enroll • Weaker post conditions • Does not allow enrollment in future courses
pre (x !=0) post (y == 10/x) & (z == 5) { y = 10/x; z = 5} Says nothing about x. Strongest Postcondition?
pre (x !=0) post (y == 10/x) & (z == 5) & (x != 0) { y = 10/x; z = 5} Strongest post condition given the precondition The stronger the pre condition, stronger the post condition. Strongest Postcondition
pre (x > 0) post (y == 10/x) & (z == 5) & (x > 0) & (y > 0) { y = 10/x; z = 5} Stronger precondition Stronger postcondition Alternative weakest/strongest pair
Multiple valid pairs • Weakest precondition relative to post condition. • Strongest post condition relative to pre condition. • A statement not associated with a unique pair that is best. • Strengthening the precondition strengthens the post condition • What is the “right pair?”
Two approaches • Start with a precondition • Find the strongest postcondition we can prove. • Start with a post condition • Find the weakest precondtion for it.
Theoretical specification point of view • Specify the result needed as a post condition. • Identify the weakest precondition needed to obtain the result. • Write a program that satisfies the pair.
Reality specification point of view • Based on what you can assume you change your expectations. • Iterative process.
Debugging/specification/ documentation point of view • Precondition of a statement should be weakest one necessary for “correct” operation of program. • Correct means no exception. • A statement that is not equivalent should not have the same pre and post condition
pre true post true { y = 10/x; z = 5} Statements are not equivalent Debugging/ specification/ documentation point of view Not the best pre and post conditions pre true post true { y = 10/x;}
pre false post false { y = 10/x; z = 5} Debugging/ specification/ documentation point of view Not the best pre and post conditions pre false post false { y = 10/x;} Statements are not equivalent
pre (x >0) post (y == 10/x) & (z == 5) & (x > 0) { y = 10/x; z = 5} Debugging/specification/ documentation point of view Statements are not equivalent pre (x >0) post (y == 10/x) & (z == 5) & (x > 0) { y = 10/x; z = 5; x = abs(x) + 1}
pre (x !=0) post (y == 10/x) & (z == 5) & (x != 0) { y = 10/x; z = 5} Debugging/ specification/ documentation point of view Best pre and post conditions
Proving programs correct point of view • Precondition can be stronger than one that is the best one for the statement from debugging/specification/documentation point of view • Allows us to derive pre and post conditions of containing statement/program
pre true post (x == 1) {x = 1} pre (x == 1) post (y == 10/x) & (z == 5) & (x == 1) { y = 10/x; z = 5} Program correctness proof
pre true post (y == 10/x) & (z == 5) & (x == 1) {x = 1; y = 10/x; x= 5} Program correctness proof
Changeable assertions • What we assert about a statement (to prove program correct) may depend on what is executed before it. • Need facilities to change assertions easily. • Proxies explained later address this.
Weakest possible condition • Implied by anything • true • p true • If p is true then true is true. • But true is always true. • So p can be any boolean expression.
Strongest possible condition • Implies anything • false • false p • If false is true then p is true • But false is never true. • So any p is implied. • “I will do this when hell freezes over”
Important equivalence • P Q !P | Q • P true !P | true true • false Q !false | Q true
Unreachable statement Asserting false • switch c { • case ‘a’: … • case ‘b’: … • default: assertfalse • }
pre (x !=0) post (y == 10/x) & (z == 5) & (x != 0) { y = 10/x; z = 5} True before and after statement Invariant
inv (x !=0) post (y == 10/x) & (z == 5) { y = 10/x; z = 5} List invariant separately Separately declared
Invariants for debugging purposes • Should never be false • False strongest invariant of all statements. • But not best for a reachable statement as it does not convey useful information • Never assert it for reachable statements if assertion not done for program proofs. • Should never involve recording variables • recording variables describe how program variables change • invariants describe how these variables do not change
sum = 0; j = 0; while (j < n) { j++; sum = sum + j; } Holds true before and after each loop iteration, that is, before and after each execution of loop body. Loop Invariant
sum = 0; j = 0; while (j < n) { j++; sum = sum + j; } Holds true before and after each loop iteration, that is, before and after each execution of loop body. Loop Invariant (edited)
inv (sum = 0j k) & (j <= n ) & (j >= 0) sum = 0; j = 0; while (j < n) { j++; sum = sum + j; } Holds true before and after each loop iteration, that is, before and after each execution of loop body. Loop Invariant
invariant x != 0 post (y == 10/x) & (z == 5) & (x != 0) void m () { y = 10/x; z = 5; } Preconditions, postconditions, invariants associated with method body Method assertions
publicclass C { int x =0; int y = 1; publicvoid incrementXAndY () { incrementX(); incrementY(); } publicint getX() { return x;} publicint getY() { return y;} incrementX() { x++;} incrementY() { y++;} } Preconditions, postconditions, invariants shared by all public methods of class Class assertions (edit)
publicclass C { int x =0; int y = 1; publicvoid incrementXAndY () { incrementX(); incrementY(); } publicint getX() { return x;} publicint getY() { return y;} incrementX() { x++;} incrementY() { y++;} } Preconditions, postconditions, invariants shared by all public methods of class Class invariant (edited)