Design by Contract Paul Ammann CS/SWE 332 © Paul Ammann, 2008 Abstraction by Specification Abstraction Implementation 1 … © Paul Ammann, 2008 Implementation N 2 Specifications Way to Define Abstractions Formality – As much as is useful – More than just English – Typically less than a language with a formal semantics – We will use industry standard (ie Javadoc) – Not intended to be a programming language! © Paul Ammann, 2008 3 Parts of a Procedural Specification Precondition /** * Returns index of element in sorted list * * @param a[] array to search; must be sorted ascending * @param x int to search for in a * @return if x in a, index of x in a else -1 * @throws NullPointerException if a is null */ public static int sortedSearch (int[]a, int x) Header Postconditions © Paul Ammann, 2008 4 Another Example No Precondition! (Precondition equals “true”) /** * Searches for index of x in a. * * @param a[] array to be searched * @param x element to search for * @return index of x if x in a * else -1 if x not in a * @throws NullPointerException if a is null public static int search (int[]a, int x) Underdetermined – what happens if x is in a more than once? © Paul Ammann, 2008 5 Yet Another Example Notice implicit treatment of duplicates /** * * * * * sorts list into ascending order. @param list list to sort @throws NullPointerException if list is null or list contains null elements @throws ClassCastException if elements in list are not mutually comparable public static void sort (List<Comparable> list) // E.g. if list = [3,1,6,1] before the call, then // list = [1,1,3,6] after the call Alternate notation: // E.g. if list = [3,1,6,1], then list_post = [1,1,3,6] © Paul Ammann, 2008 6 What does a Contract Look Like? Consider the triple: {P} S {Q} – P is the precondition (Requires clause) – Q is the postcondition (Effects clause) – S is the program text The Customer (client) is obligated to establish P. The Implementor (service) may assume P The Customer is entitled to Q The Implementor is obligated to provide Q That’s it! © Paul Ammann, 2008 7 What happens when a Contract Breaks? If everyone does their job, there is no problem! If the precondition is not satisfied, the Customer is wrong! (The client has a bug). If the precondition is satisfied, but the postcondition is not, then the Service is wrong (The server has a bug). The Client can’t do the Server’s job! The Server can’t do the Client’s job! © Paul Ammann, 2008 8 Application of Contract Model to Debugging Suppose you are fixing a fault in a program. – What justification is there for a proposed change? Example Context: code considered correct ..... {P} code identifed as wrong vs. proposed correct code ..... {Q} more code considered correct © Paul Ammann, 2008 9 Example /** * returns number of zeroes in arr. * @param arr[] array to count zeroes in * @throws NullPointerException if arr is null */ public static int numZero (int[] arr) { int count = 0; {inv: count has # zeros in arr[0..-1]} for (int i=1; i < arr.length; i++) { {inv: count has # zeros in arr[0..i-1]} if (arr[i] == 0) {count++} }return count;} © Paul Ammann, 2008 10 What does the Client like? Since preconditions are Client obligations, the Client would prefer not to have any! From the Client’s perspective, “true” is the best precondition. In general, weaker preconditions are better. The Client is happy to have any postcondition that is strong enough to meet the Client’s needs. © Paul Ammann, 2008 11 What does the Server like? Since preconditions are Server benefits, the Server would prefer to have lots of them! From the Server’s perspective, “false” is the best precondition. In general, stronger preconditions mean an easier job with the implementation. The Server prefers weak postconditions. Each additional constraint in a postcondition is an additional obligation on the Server. © Paul Ammann, 2008 12 Problems with Eliminating Preconditions Forcing the Server to handle “weird” cases can lead to inefficient, bulky (read “error prone”) code. For “local” use, therefore, preconditions can be extremely powerful (and appropriate). Example: Consider the “partition” method in a quicksort routine. It would be weird to handle the case where the array indices were out of bounds. © Paul Ammann, 2008 13 More Problems with Eliminating Preconditions What if the Implementer can’t provide a good “default” (ie Defensive Programming)? Consider this (undocumented!) code: public static double sqrt (double x) { if (x < 0) { handle problem somehow return some value (what?) } else { proceed with normal square root computation return y such that y*y is approximately x } } © Paul Ammann, 2008 14 Dissecting the Square Root Example What could possibly be a correct “default”? – Printing an error message? • Not a comforting thought to certain end users (ie pilots). What could possibly be a reasonable return value? The Lesson: The Server is not in a position to define behavior. That’s the Client’s job. (through the contract mechanism). © Paul Ammann, 2008 15