1 / 42

Contracts and Invariants

Contracts and Invariants. Section 6.2 (JIA’s). Design by Contract --- DBC. Each class interface defines a set of services via its public methods The declaration of a method what the user cares about in the API or javadoc documentation pages defines only the type and not behavior

wesley
Télécharger la présentation

Contracts and Invariants

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Contracts and Invariants Section 6.2 (JIA’s)

  2. Design by Contract --- DBC • Each class interface defines a set of services via its public methods • The declaration of a method • what the user cares about in the API or javadoc documentation pages • defines only the type and not behavior • Behavior = what happens when method is run • When can I call it? What happens if I do? • One should not write a class without a formal contract • lists the internal consistency conditions that the class will maintain (the invariants) • for each method • the correctness conditions that are the responsibility of the client (the precondition) • and those which the operation promises to establish in return (the postcondition) • Missing contracts  • Silence on some aspects of behavior • Multiple interpretations • Contradictions

  3. Design by Contract --- DBC • Methods have preconditions and postconditions; classes have invariants • “When you call me, the following must be true” • “If the preconditions are satisfied, I guarantee the following will be true when I return” • Thus the two make up a contract: If you do this, I promise to do that”

  4. Pre and Post Conditions • A precondition is a Boolean expression that must hold when the method is invoked • i.e. a method may not be invoked when the preconditions is false • preconditions are guaranteed by the caller • A postcondition is a Boolean expression that must hold when the method invocation returns • postconditions are guaranteed by the callee

  5. Contract of a Method • Documented using special tags (most tags are not supported by JavaDoc) • /** • * JAVADOC Documentation • *@pre precondition • *@post postcondition • */ • public … someMethod(){} • Those tags may occur multiple times for any single method • in such cases, the conjunction of all Boolean expression would serve as the pre and post conditions

  6. Contract of a Method • The following special tags are used in pre- and post-conditions • @resulta variable holding the return value of a method • @nochangea Boolean expression implying that the state of the object is not changed by the method • in postconditions for accessors • Can also use the following operators •  logical implication (a  b is true iff a is false or both are true) • logical equivalence (ab is true iff both are either true or false) … can == instead

  7. Example 1 • /** • * Returns the number of elements in • * an ArrayList • * • * OTHER JAVADOC TAGS • *@pre true • *@post @result==list.size() • *@post @nochange//no change for the state of the object (i.e. an accessor or a getter method) • */ • public int size(){}

  8. Example 2 • /** • * Returns true iff the list is empty • * • * OTHER JAVADOC TAGS • *@pre true • *@post @result == (size() <= 0) // this is a condition so that is why we use == instead of = • *@post @nochange • */ • public boolean isEmpty (){}

  9. Example 3 • /** • * Returns the 1st element in the list • * • * OTHER JAVADOC TAGS • *@pre !isEmpty() • *@post @result == list.get(0) // this is a condition so that is why we use == instead of = • *@post @nochange • */ • public Object head(){…} • Last()?

  10. Example 4 • /** • * Returns the last element in the list • * • * OTHER JAVADOC TAGS • *@pre !isEmpty() • *@post @result == list.get(size()-1) • *@post @nochange //no change for the state of the object (i.e. an accessor or a getter method) • */ • public Object last()

  11. Mutators • A mutator is a method that changes the state of the object (setter) • @post @nochange for accessors • Need to distinguish between the state of the object before and after the method invocation • values of expressions in the postcondition are evaluated w.r.t. the after state of the object (i.e. after method returns) • Add a new item at top and return it • @post @result == list(size()-1) • To refer to object immediately before the method is invoked, we use the pre-state notation • expression@pre • Add a new item to list  increase size • E.g. @post size() == size()@pre + 1

  12. Collections • Contracts involving a collection of objects (i.e. list, vector, array, etc … ) often require quantified expressions • Universal quantification • Holds on every object in the collection • @forall x: [Range]@Expression • Existential quantification • Holds on at least one object in the collection • @exists x: [Range]@Expression • x is a variable over Range • Range specifies the collection of objects • Expression is a Boolean expression

  13. Specifying Ranges • [m..n] • Where m and n are integer expressions • @post @forall k:[0..size()-1)]@SOME_COND • ClassName • Defines range of all instances of the class • @post @forall k:CAR@SOME_COND • Expression • Evaluates to a collection like a set, bag, list, etc … • @post @forall k:{“Red”,”Green”,”Blue”}@SOME_COND

  14. Example 5 • /** • * Inserts a new element at the ith position only if item is not * null • * • * OTHER JAVADOC TAGS • *@pre item !=null && i>=0 && i<size() • *@post size() == size()@pre + 1 • *@post @forall k:[0..size()-1]@ • * ((k<i  list.get(k) == list@pre.get(k))&& • * (k==i list.get(k) == item)&& • * (k>i list.get(k) == list@pre.get(k-1))) • */ • public void insert(Object item, int i) • Try • public void insertHead(Object item) //i.e. at location 0 • public void insertTail(Object item) //i.e. at location size()-1

  15. Example 6 • /** • * Inserts a new element at the head only * if item is not null • * • * OTHER JAVADOC TAGS • *@pre item !=null • *@post size() == size()@pre + 1 • *@post @forall k: [0..size()-1]@ • * ((k==0 list.get(k) == item) && • * (k>0  list.get(k) == list@pre.get(k-1))) • */ • public void insertHead(Object item)

  16. Example 7 • /** • * Inserts a new element the tail only if • * item is not null • * • * OTHER JAVADOC TAGS • *@pre item !=null • *@post size() == size()@pre + 1 • *@post @forall k: [0..size()-1]@ • * ((k<size()-1 list.get(k)==list.get@pre(k)) && • * (k==size()-1 list.get(k)==list.get(size()-1)) • */ • public void insertTail(Object item) • Try • public Object remove(inti) • public Object removeHead() • public Object removeTail()

  17. Example 8 • /** • * Remove and return the element at position * index • * • * OTHER JAVADOC TAGS • *@pre !isEmpty() && index >=0 && index <size() • *@post size() == size()@pre-1 • *@post @result == list@pre.get(index) • *@post @forall k: [0..size()-1] @ • *((k< index  list.get(k)==list@pre.get(k))&& • *(k>= index  list.get(k)==list@pre.get(k+1))) • */ • public Object remove(int index)

  18. Example 9 • /** • * Remove and return the Head item • * • * OTHER JAVADOC TAGS • *@pre !isEmpty() • *@post size() == size()@pre-1 • *@post @result == list.get(0)@pre • *@post @forall k: [0..size()-1] @ • * (list.get(k) == list@pre.get(k+1)) • */ • public Object removeHead()

  19. Example 10 • /** • * Remove and return the Tail item • * • * OTHER JAVADOC TAGS • *@pre size() > 0 • *@post size() = size()@pre-1 • *@post @result == list.get(size()-1)@pre • *@post @forall k: [0..size()-1] @ • * (list.get(k)==list@pre.get(k)) • */ • public Object removeTail()

  20. Invariants of Classes • Two states for objects • Objects in the transient state • Being manipulated • i.e. 1 or more MUTATOR methods of its class are being executed • Objects in the stable state • Constructed • Not being manipulated by a MUTATOR • A class invariant is a condition that always applies on any object of the class whenever it is a stable condition • An object is said to be a in well-formed state if all class invariants hold

  21. Invariants of Classes • /** • * JAVADOC DESCRIPTION • * @invariant Expression • */ • public class AClass { • //.. • } • Where the Expression is a Boolean expression • @ invariant tag could occur multiple times • Conjunction of all needs to be taken

  22. Example 1 • /** • * JAVADOC DESCRIPTION • * @invariant (age > 0 && age < 150) • * @invariant (balance >= 0) • */ • class Account { • private String name; • private String acct#; • private int age; • private double balance; • private void deposit(…) { /* ... */ } • public void withdraw(…) { /* ... */ } • }

  23. Example 2 • Class that maintains a sorted intlist[] • /** • *@invariant @forall x: [0..size()-2] @list[x] <= list[x+1] • */

  24. Example 3 • class MyStack { • private Object[] elems; • private int top, max; // top = index of last array element + 1 (0 initially) // max = maximum array capacity • public MyStack(int size) { • top = 0; • max = size; • elems = new Object[size];} • public boolean isFull() { • return top == max;} • public boolean isEmpty() { • return top == 0;} • public void push(Object obj) { • elems[top++] = obj;} • public Object pop() { • return elems[--top];} • } // End MyStack

  25. /**   * @invariant (top >= 0 && top <= max) */ class MyStack { private Object[] elems; private int top, max; /** @pre (size > 0) @post (top==0 && max == size && elems!=null) */ public MyStack(int size) { top=0 max = size; elems = new Object[size];} /** @pre true @post (@result  (top == max)) @post @nochange */ public boolean isFull() { return top == max;} /** @pre true @post (@result  (top == 0)) @post @nochange */ public boolean isEmpty() { return top == 0; } /** @pre !isFull() @post (top == top@pre + 1) @post @forall k:[0..top-1]@ ( (k==top-1  elems[k]==obj) (k<top-1  elems[k]==elems@pre[k])) */ public void push(Object obj) { elems[top++] = obj;} /** @pre !isEmpty() @post (top == top@pre - 1) @post @result == elems[top@pre-1]@pre @post @forall k:[0..top-1]@ elems[k] == elems@pre[k] */ public Object pop() { return elems[--top];} } // End MyStack Example 3

  26. Assertions • Used to perform run-time checking of method preconditions, postconditions and class invariants • For Preconditions • At entry point of each method • Defensive programming • For Postconditions: • At exit point of each method (before returning) • Assists in unit testing and debugging • For Invariants: • boolean well_formed() method • At exit point of every constructor • At entry and exit point of every public mutator method • Acessors?

  27. Assertions • A Boolean condition given at a location of program • Should be true whenever the flow of execution reaches that location • assert Assertion_Condition; • E.g. assert top < max • Has no effect if the assertion is true • Throws an AssertionError exception if false (Unchecked) • Run with –ea option • java –ea MyStack

  28. Example 1 • /** • * Returns the head of the list • * @pre !isEmpty() • * @post @result == element(0) • * @post @nochange • */ • public Object head(){ • assert well_formed(); //for invariant • assert !isEmpty(); • Object result = element(0) • assert result .equals(element(0)); • assert well_formed(); //for invariant • return result; • }

  29. Example 2b • /** • * Inserts a new element at the ith position • * • * OTHER JAVADOC TAGS • *@pre item !=null && i>= 0 && i<size() • *@post size() = size()@pre + 1 • *@post @forall k:[0..size()-1)]@ • *(k<i  list.get(k) == list@pre.get(k))&& • *(k==i item == list.get(k))&& • *(k>i list.get(k) == list@pre.get(k-1)) • */ • public void insert(Object item, int i){ • …}

  30. Assertions • Postconditions that deal with prestates are more difficult to assert • Need to save the values of objects or variables whose prestates are required • Manual … very tedious • Clone objects • The cloned object’s class must implement Cloneable • Point p1 = new Point(); • Point p2 = (Point) p1.clone(); • Different than copying? • Point p2 = p1; • Section 6.3.4 JAI’s

  31. Copying vs. Cloning • Point p1 = new Point(); • Point p2 = p1; • Point p1 = new Point(); • Point p2 = (Point) p1.clone();

  32. Cloning • When you invoke clone(), it should either: • throw CloneNotSupportedException • If the object doesn't implement the Cloneable interface • return an Object reference to a copy of the object upon which it is invoked, • If the object implements the Cloneable interface • all the fields initialized to values identical to the object being cloned • In class Object, the clone() method is declared protected • If all you do is implement Cloneable, only subclasses and members of the same package will be able to invoke clone() on the object • To enable any class in any package to access the clone() method, you'll have to override it and declare it public, as is done next

  33. Cloning • In class Object • protected Object clone () throws CloneNotSupportedException • When you invoke clone(), it should either: • throw CloneNotSupportedException • If the object doesn't implement the Cloneable interface • checked exception • return an Object reference to a copy of the object upon which it is invoked • If the object implements the Cloneable interface • all the fields initialized to values identical to the object being cloned

  34. class CoffeeCup implements Cloneable { • private int innerCoffee; • public void add(int amount) { • innerCoffee += amount; } • public int releaseOneSip(int sipSize) { • int sip = sipSize; • if (innerCoffee < sipSize) { sip = innerCoffee; } • innerCoffee -= sip; • return sip; } • public int spillEntireContents() { • int all = innerCoffee; • innerCoffee = 0; • return all; } }

  35. make a copy of class CoffeeCup • class Example1 { • public static void main(String[] args) { • CoffeeCup original = new CoffeeCup(); • // Original contains 75 ml of coffee • original.add(75); • CoffeeCup copy; • try{ copy = (CoffeeCup)original.clone(); } • Catch(CloneNotSupportedExceptioncnse) { … } // Copy now contains 50 ml of coffee • copy.releaseOneSip(25); • intorigAmount = original.spillEntireContents(); • intcopyAmount = copy.spillEntireContents(); • System.out.println("Original has " + origAmount + " ml of coffee."); • System.out.println("Copy has " + copyAmount + " ml of coffee."); } }

  36. Cloning In General • In class Object, the clone() method is declared protected • If all you do is implement Cloneable, only subclasses and members of the same package will be able to invoke clone() on the object • To enable any class in any package to access the clone() method, you'll have to override it and declare it public

  37. class CoffeeCup implements Cloneable { • private intinnerCoffee; • public Object clone() { • try{ return super.clone();} • Catch(CloneNotSupportedException …){ …} } • public void add(int amount) { • innerCoffee += amount; } • public intreleaseOneSip(intsipSize) { • int sip = sipSize; • if (innerCoffee < sipSize) { sip = innerCoffee; } • innerCoffee -= sip; • return sip; } • public intspillEntireContents() { • int all = innerCoffee; • innerCoffee = 0; • return all; } }

  38. make a copy of class CoffeeCup • class Example1 { • public static void main(String[] args) { • CoffeeCup original = new CoffeeCup(); • original.add(75); // Original contains 75 ml of coffee • CoffeeCup copy = (CoffeeCup)original.clone(); • copy.releaseOneSip(25); // Copy now contains 50 ml of coffee • int origAmount = original.spillEntireContents(); • int copyAmount = copy.spillEntireContents(); • System.out.println("Original has " + origAmount + " ml of coffee."); • System.out.println("Copy has " + copyAmount + " ml of coffee."); } }

  39. Objects that Contain Other Objects • Object's clone() will copy the value of each instance attribute from the original object into the corresponding instance variables of the copy object • Values of primitive attributes are copied • Values of reference attributes are duplicated • Shallow copying vs. deep copying • If one of those variables is an object reference, the copy object will get a duplicate reference to the same object • Immutable (e.g. String or object with no mutators) • Constant

  40. Primitive data types in Java: integer (byte, short, int, & long), floating-point ( float & double), character (char) and boolean (boolean) Immutable and constant objects

  41. class CoffeeCup implements Cloneable{ • private Coffee innerCoffee = new Coffee(0); • public Object clone() • { • try{ • CoffeeCup copy = (CoffeeCup) super.clone(); • //clone attributes of reference type explicitly • copy.innerCoffee = (Coffee) innerCoffee.clone(); • return copy; • } • Catch(CloneNotSupportedException){…} • } • Classes that already implement Cloneable • http://java.sun.com/javase/6/docs/api/java/lang/class-use/Cloneable.html

  42. Beyond Contracts • Writing assertions while programming • one of the fastest and most effective ways to detect and correct bugs • serve to document and enhance maintainability • Don’t use assertions for error handling (e.g. exceptions) • Assertions check for things that should never happen

More Related