Data Abstraction SWE 619 Software Construction Last Modified, Spring 2009 Paul Ammann Data Abstraction Abstract State (Client State) Representation State (Internal State) Methods Constructors (create objects) Producers (return immutable object) Mutators (change state) Observers (report about state) 2 Motivation Why data abstraction? Why hide implementation? Client code breaks Malicious or clueless clients don’t depend on/mess up the state Maintain properties like rep invariant Hence, encapsulation 3 IntSet and Poly Poly 5+3x+8x3, 4x+6x2 {x1, …, xn} c0+c1x+… Mutable Immutable Students find this Students find this easy to implement harder to implement but a better approach IntSet {4,6} {}, {3,5,9}, 4 Specification of IntSet public class IntSet { //Overview: IntSets are mutable, unbounded sets of integers // A typical IntSet is {x1, …, xn} //constructors public IntSet() //Effects: Initializes this to be empty //methods public void Insert (int x) // Modifies: this // Effects: Adds x to this, i.e., this_post = this + {x} 5 Specification of IntSet (2) public void remove (int x) //Modifies: this //Effects: Removes x from this, i.e., this_post=this –{x} public boolean isIn (int x) //Effects: If x is in this, returns true, else returns false public int size () //Effects: Returns the cardinality of this public int choose () throws EmptyException // Effects: If this is empty, throws EmptyException else // returns an arbitrary element of this 6 Remember! Don’t mention internal state in constructor or method specifications Always override toString() (don’t show the rep) Client should not see in-between state, all operations atomic this_post after execution of procedure 7 Set Notation – figure 5.3 A set is denoted {x1, … xn} Set union: t = s1 + s2 Set difference: t = s1 – s2 Set intersection: t = s1 & s2 Cardinality |s| denotes the size of set s Set membership: x in true if x element of set s Set former: t = { x | p(x)} is the set of all x such that p(x) is true These few notions are extremely powerful! 8 Specification of Poly public class Poly { // Overview: Polys are immutable polynomials with integer co// -efficients. A typical Poly is c0+c1x+ … //constructors public Poly() // Effects: Initializes this to be the zero polynomial public Poly (int c, int n) throws NegativeExponentException // Effects: If n<0 throws NegativeExponentException // else initializes this to be the Poly cxn 9 Specification of Poly (2) //methods public int degree () //Effects: Returns the degree of this (the largest exponent // with non zero coeff. Returns 0 if this is the zero Poly public int coeff (int d) //Effects: Returns the coeff of the term of this with exp. d (what if d > degree? what if d < 0?) public Poly add (Poly q) throws NullPointerException //Effects: If q is null throws NPE else // returns the Poly this + q public Poly mul (Poly q) throws NPE //Effects: if q is null throws NPE, else returns this * q 10 Poly in detail 5+3x+8x3 can’t build with the constructor Only zero or monomial NegativeExponentException No modifies clause: Immutable No mutators How does it support add, remove, multiply etc.? 11 Collections – A Slight Diversion D U P L I C A T E S Ordering N Y N Y Set InjectiveList Bag Vector, List One collection is often implemented with another. 12 Implementation (IntSet) Rep: Vector Abstract state: Set Design decision (els never null) Use of special value in getIndex, justified? Design decision, duplicates in insert Why is remove as shown? 13 Implementation of IntSet (2) private Vector els; // the rep public void insert (int x) { //Modifies: this (NOT els!) //Effects: Adds x to the elements of this (NOT els!) Integer y = new Integer(x); if (getIndex(y) < 0) els.add(y); } private int getIndex(Integer x) { // Effects: If x is in this return index where x appears // else return -1 for (int i=0; i < els.size(); i++) if (x.equals(els.get(i))) return i; return -1; } 14 Implementation of IntSet (3) public void remove (int x) { //Modifies: this //Effects: Remove x from this int i = getIndex(new Integer(x)); if (i < 0) return; els.set(i, els.lastElement()); els.remove(els.size() - 1); } public int choose() { // Effects: If this empty throw EE else return arbitrary element of this if (els.size() == 0) throw new EE(“IntSet.choose”); return ((Integer) els.lastElement()).intValue(); } 15 Implementation of Poly (1) private int[] trms; private int deg; public Poly() { //Effects: Initializes this to be the zero polynomial trms = new int[1]; trms[0] = 0; deg = 0; } public Poly (int c, int n) throws IAE { //Effects if n < 0 throw IAE else initializes this to cx^n if (n < 0) throw new IAE(“Poly.constructor”); if (c ==0) { trms = new int[1]; trms[0] = 0; deg = 0; return} trms = new int[n+1]; deg = n; for (int i = 0; i < n; i++) trms[i] = 0; trms[n] = c; } private Poly (int n) { trms = new int[n+1] deg = n;} 16 Implementation of Poly (2) public int degree() { //Effects: Return degree of this, ie the largest exponent // with a nonzero coefficient. Returns 0 if this is the zero Poly return deg;} public coef (int d) { // Effects: Returns the coefficient of the term of this whose exp is d if (d < 0 || d > deg) return 0; else return trms[d];} // implementations of add, sub, minus, mul 17 Abstraction Function Abstract state {x1, …, xn} Representation state? Vector els = [y0, y1, …, yn] Representation state is designer’s choice. Clients don’t see rep (representation state), only see abstract state Clients don’t care for rep, as long as it satisfies properties of abstract state Implementer can change rep at any time! 18 Abstraction Function (IntSet) Abstraction function is a mapping from representation state to abstract state Abstraction function for IntSet: AF(c) = c.els[i] | 0 i < c.els.size() } If duplicates allowed, what should AF(c) be? What if null is mapped to {}? 19 AF() for IntSet Abstract State (IntSet s) s = {} s = {1, 2} s = {1} els = [null, 5] els = [] s = {1, 7} AF() els = [1, 2] els = null els = [“cat”, “hat”] els = [2, 1] els = [7, 1, 7] Representation State (Vector els) 20 Rep Invariant Rep Invariant is the expression of combined restrictions on representation c.els != null No duplicates in c.els All entries in c.els are Integers No null entries English descriptions are fine! These are DESIGN DECISIONS. 1. 2. 3. 4. For example, we COULD allow duplicates... 21 Additional Methods clone() wrong in Liskov; we will use Bloch toString() Implementation of abstraction function equals() non standard wrt Java - understand why 1. 2. 3. 1. 2. 3. In terms of mutability– different for mutable and immutable types Bias towards correctness Three different things are required: == // This checks if same object equals() // for immutable only (same abstract state) similar() // Mutable (same current abstract state) // Not implemented in Java 22 equals() Involves three important criteria: reflexivity, symmetry, transitivity Often difficult to implement For abstract extensions of instantiable superclasses, impossible to implement! Details later... toString Should match with “typical object” Trick: Do it backwards - implement toString() first and then write the abstraction function. 23 Mutable/Immutable Transform Stack example in Bloch Transform to an immutable version Mutable We should be fine with immutable stacks: Immutable Stack s = new Stack(); s = s.push(“cat”); s =s.push(“dog”); How to tranform: SWE 619 24 Mutator Producer Consider a mutator method in class C: public void m(T t) or public S m(T t) What do the corresponding immutable methods look like? public C m(T t) or public ??? m(T t) Second needs to be split into two methods: Example: pop() vs. pop(), top() in Stack SWE 619 25