Presentation is loading. Please wait.

Presentation is loading. Please wait.

Abstraction functions, Reasoning About ADTs

Similar presentations


Presentation on theme: "Abstraction functions, Reasoning About ADTs"— Presentation transcript:

1 Abstraction functions, Reasoning About ADTs
Based on material by Michael Ernst, University of Washington

2 Practice Defensive Programming
Assume that you will make mistakes Write code to catch them On method entry Check rep invariant (i.e., call checkRep()) Check preconditions (requires clause) On method exit Check rep invariant (call checkRep()) Check postconditions Checking rep invariant helps find bugs Reasoning about rep invariant helps avoid bugs Spring 18 CSCI 2600, K. Kuzmin, A Milanova (based on notes by Michael Ernst)

3 Aside: Invariants Why focus so much on invariants? Software is complex
Loop invariants, rep invariants, immutability, which is a kind of invariant (immutable ADTs; modifies and effects clauses in the specification) Software is complex Lots of interactions between different “modules”. Interactions is what makes reasoning difficult Lots of “moving parts” (i.e., lots of changes) Spring 18 CSCI 2600, K. Kuzmin, A Milanova

4 Aside: Invariants Invariants are properties that stay unchanged. Reduce intellectual complexity If we know that some property stays unchanged, we can focus on other properties Reducing the number of things we need to think about can be of great benefit Spring 18 CSCI 2600, K. Kuzmin, A Milanova (based on slides by Michael Ernst)

5 Connecting Implementation to Specification
Representation invariant: Object  boolean Indicates whether data representation is well-formed. Only well-formed representations are meaningful Defines the set of valid values Abstraction function: Object  abstract value What the data representation really means E.g., array [2, 3, -1] represents –x2 + 3x + 2 How the data structure is to be interpreted But how do we know that our implementation is correct? Spring 18 CSCI 2600, K. Kuzmin, A Milanova (based on slides by Michael Ernst)

6 Abstraction Function: rep  abstract value
The abstraction function maps valid concrete data representation to the abstract value it represents. I.e., domain is all reps that satisfy the rep invariant AF: Object  abstract value The abstraction function lets us reason about behavior from the client perspective Spring 18 CSCI 2600, K. Kuzmin, A Milanova (based on a slide by Michael Ernst)

7 Rep Invariant Excludes Meaningless Concrete Values
Disallows meaningless values E.g., a RightTriangle cannot have base = -2 Ensures fields are properly synchronized volume and contents in BallContainer amount and transactions list in Account degree and coeffs array in Poly Ensures specific data structure constraints A Tree cannot have cycles Other correctness constraints 0 <= index < names.length, names!=null

8 Abstraction Function Example
class Poly { // Rep invariant: degree = coeffs.length-1 // coeffs[degree] != 0 private int[] coeffs; private int degree; // Abstraction function: coeffs [a0,a1,…adegree] // represents polynomial // adegreexdegree + … + a1x + a0 // E.g., array [-2,1,3]  3x2 + x - 2 // Empty array represents the 0 polynomial … Because the AF is defined only on valid rep, we don’t have to worry that the last element of the array is 0. Spring 18 CSCI 2600, K. Kuzmin, A Milanova

9 Another Abstraction Function Example
class IntSet { // Rep invariant: // data contains no nulls and no duplicates private List<Integer> data; // Abstraction function: data [a1,a2,…an] // represents the set { a1, a2, … an }. // Empty list represents {}. public IntSet() … Again, valid rep. Spring 18 CSCI 2600, K. Kuzmin, A Milanova

10 Abstraction Function: mapping rep to abstract value
Abstraction function: Object  abstract value I.e., the object’s rep maps to abstract value IntSet e.g.: list [2, 3, 1]  { 1, 2, 3 } Many objects map to the same abstract value IntSet e.g.: [2, 3, 1]  { 1, 2, 3 } and [3, 1, 2]  { 1, 2, 3 } and [1, 2, 3]  { 1, 2, 3 } Not a function in the opposite direction One abstract value maps to many objects Why is it that we are not interested in a function in the opposite direction: i.e., abstract Value -> Object? Spring 18 CSCI 2600, K. Kuzmin, A Milanova

11 Another (Implementation of) IntSet
What if we dropped the “no duplicates” constraint from the rep invariant class IntSet { // Rep invariant: data contains no nulls private List<Integer> data; Can we still represent the concept of the IntSet? (Remember, an IntSet is a mutable set of integers with no duplicates.) Spring 18 CSCI 2600, K. Kuzmin, A Milanova

12 Yes. First, we have to change the abstraction function
class IntSet { // Rep invariant: data contains no nulls private List<Integer> data; // Abstraction function: List data // represents the smallest set // { a1, a2, … an } such that each ai is // in data. Empty list represents {}. public IntSet() … Spring 18 CSCI 2600, K. Kuzmin, A Milanova

13 Another IntSet … [1,1,2,3]  { 1, 2, 3 } [1,2,3,1]  { 1, 2, 3 } etc.
class IntSet { // Rep invariant: data contains no nulls private List<Integer> data; [1,1,2,3]  { 1, 2, 3 } [1,2,3,1]  { 1, 2, 3 } etc. There are many objects that correspond to the same abstract value Spring 18 CSCI 2600, K. Kuzmin, A Milanova

14 Another IntSet We have to change implementation of operations as well
What is the implication for add(int x) and remove(int x)? For size()? add(int x) no longer needs check contains(x). Why? remove(int x) must remove all occurrences of x in data. Why? What about size()? What else? How about equals()??? Spring 18 CSCI 2600, K. Kuzmin, A Milanova

15 Correctness Abstraction function allows us to reason about the implementation  Abstract operation:  If we take a concrete object, apply AF, get Abstract value. Abstract value Abstract value’ AF: AF: Concrete operation (i.e., our implementation of operation):   Concrete object Concrete object’ Spring 18 CSCI 2600, K. Kuzmin, A Milanova

16 IntSet Example { 1,2,3 } { 2,3 } [2,1,1,2,3] [2,2,3]
Abstract remove(1): this – { 1 }   { 1,2,3 } { 2,3 } AF: AF: If we take a concrete object, apply AF, get Abstract value. Concrete remove(1)   [2,1,1,2,3] [2,2,3] Creating concrete object: Establish rep invariant Establish abstraction function After every operations: Maintains rep invariant Maintains abstraction function Spring 18 CSCI 2600, K. Kuzmin, A Milanova

17 Aside: the Rep Invariant
Which implementation is better class IntSet { // Rep invariant: // data has no nulls and no duplicates // methods establish & maintain invariant // and original abstraction function or // Rep invariant: data has no nulls // methods maintain this weaker invariant // and new abstraction function

18 Aside: the Rep Invariant
Often one role of the rep invariant is to simplify the abstraction function (by limiting valid concrete values which limits the domain of the abstraction function) Consequently, rep invariant simplifies implementation and reasoning! Spring 18 CSCI 2600, K. Kuzmin, A Milanova

19 Benevolent Side Effects
Another implementation of IntSet.contains: public boolean contains(int x) { int i = data.indexOf(x); if (i == -1) return false; // move-to front optimization // speeds up repeated membership tests Integer y = data.elementAt(0); data.set(0,x); data.set(i,y); } Mutates rep, but does not change abstract value! E.g., contains(4) will cause [1,2,4] to change to [4,2,1]. Both map to the same abstract value, the set {1,2,4}. This is important, because we may treat contains as pure method (i.e., side-effect free method) from the client’s perspective. This is because contains does not change visible state in ways that are important to the client. Thus, the client mustn’t worry about contains causing unintended side effects in their code. Spring 18 CSCI 2600, K. Kuzmin, A Milanova (based on slide by Michael Ernst)

20 ADT is a Specification Specification of contains remains
// returns: (x in this) boolean contains(int x); The specification reflects modification/effects on abstract state (i.e., specification fields), not concrete state (i.e., representation fields)! How would you write the spec then? The spec reflects that the mutation to rep was only incidental. Spring 18 CSCI 2600, K. Kuzmin, A Milanova

21 Another Example: String.hashCode()
// returns: the hashCode value of this string public int hashCode() { int h = this.hash; // rep. field hash if (h == 0) { // caches the hashcode char[] val = value; int len = count; for (int i = 0; i < len; i++) { h = 31*h + val[i]; } this.hash = h; // modifies rep. field } return h; } Spring 18 CSCI 2600, K. Kuzmin, A Milanova

22 Writing an Abstraction Function
The domain is all representations that satisfy the rep invariant Rep invariant simplifies the AF by restricting its domain The range is the set of abstract values Denoted with specification fields and derived spec fields Relatively easy for mathematical concepts like sets Trickier for “real-world” ADTs (e.g., Person, Meeting) Specification fields and derived specification fields help describe abstract values Spring 18 CSCI 2600, K. Kuzmin, A Milanova (based on slide by Michael Ernst)

23 Specification Fields Describe abstract values. Think of the abstract value as if it were an object with fields E.g., math concept of a LineSegment start-point and end-point are specification fields length is a derived specification field Can be derived from spec fields but it’s useful to have Range of AF and specs of operations are in terms of specification fields

24 Specification Fields Often abstract values aren’t clean mathematical objects E.g., concept of Customer, Meeting, Item Define those in terms of specification fields: e.g., a Meeting can be specified with specification fields date, location, attendees In general, specification fields (the specification) are different from the representation fields (the implementation) Spring 18 CSCI 2600, K. Kuzmin, A Milanova

25 ADTs and Java Language Features
Java classes Make operations of the ADT public methods Make other operations private Clients can only access the ADT operations Java interfaces Clients only see the ADT operations, nothing else Multiple implementations, no code in common Cannot include creators (constructors) or fields Spring 18 CSCI 2600, K. Kuzmin, A Milanova (based on slide by Michael Ernst)

26 ADTs and Java Language Features
Both classes and interfaces can apply Write and rely upon careful ADT specifications When coding, prefer interface types over specific class types E.g., we used List<Integer> data not ArrayList<Integer> data to declare the rep field. Why? Spring 18 CSCI 2600, K. Kuzmin, A Milanova

27 Implementing an ADT: Summary
Rep invariant Defines the set of valid objects (concrete values) Abstraction function Defines, for each valid object, which abstract value it represents Together they modularize the implementation Can reason about operations in isolation Neither is part of the ADT abstraction!!! Spring 18 CSCI 2600, K. Kuzmin, A Milanova (slide by Michael Ernst)

28 Implementing an ADT: Summary
In practice Always write a rep invariant! Write an abstraction function when you need it Write a precise but informal abstraction function A formal one is hard to write, and often not that useful As always with specs: we look for the balance between what is “formal enough to do reasoning” and what is “humanly readable and useful” Spring 18 CSCI 2600, K. Kuzmin, A Milanova (slide by Michael Ernst)

29 Exercise The mathematical concept of the LineSegment
Choose spec fields (abstraction) Choose rep fields Write rep invariant Write abstraction function Spring 18 CSCI 2600, K. Kuzmin, A Milanova

30 LineSegment Solution (sketch)
Abstraction: LineSegment end_point … } Spring 18 CSCI 2600, K. Kuzmin, A Milanova

31 LineSegment Solution (sketch)
Implementation: class LineSegment { float x1, y1; float x2, y2; // Rep invariant: !(x1==x2 && y1==y2) // AF: {x1,y1,x2,y2} represents the // line segment with start_point (x1,y1) // and end_point (x2,y2) }

32 LineSegment Solution (sketch)
Stronger rep invariant to simplify AF and implementation: class LineSegment { float x1, y1; float x2, y2; // Rep invariant: (x1,y1) is lexicographically // smaller than (x2,y2) i.e., // (x1 < x2) || (x1 == x2 && y1 < y2) // AF: … }

33 Exercise Suppose we decided to represent our polynomial with a list of terms: private List<Terms> terms; Write the abstraction function Use e(terms[i]) to refer to exponent of ith term Use c(terms[i]) to refer to coefficient of ith term Be concise and precise

34 How to Design Your Code The hard way: Start hacking. When something doesn’t work, hack some more The easier way: Plan carefully Write specs, rep invariants, abstraction functions Write tests (first!), reason about code, refactor Less apparent progress at first, but faster completion times, better product, less frustration Spring 18 CSCI 2600, K. Kuzmin, A Milanova (based on a slide by Michael Ernst)

35 How to Verify Your Code The hard way: hacking, make up some inputs
An easier way: systematic testing Black-box testing techniques (more next time) High white-box coverage (more next time) JUnit framework Also: reasoning, complementary to testing Prove that code is correct Implementation satisfies specification Rep invariant is preserved We will write informal proofs

36 Uses of Reasoning Goal: show that code is correct
Verify that the implementation satisfies its specification. Hard! Forward reasoning: show that if precondition holds, postcondition holds Backward reasoning: compute weakest precondition, then show stated precondition implies the weakest precondition Today: prove that rep invariant always holds. (1) This is sometimes easy, sometimes hard. (2) We will use informal proofs.

37 Goal: Show that Rep Invariant Is Satisfied
Prove that all objects permitted by our implementation satisfy the rep invariant Sometimes easier than testing, sometimes harder. How would you “test” rep invariant? You should know how to use it appropriately Create many representative instances, call a bunch of methods on them, running checkRep in the beginning and end of each method. Challenging to pick representative instances. Pick such that there is good chance of uncovering errors. Pick such that we have good coverage of space, and can generalize with reasonable hope: if rep invariant remained satisfied for these instances then it would remain satisfied for the rest of the objects.

38 Verify that Rep Invariant Is Satisfied
We have infinitely many objects, but limited number of operations How do we prove all objects satisfy rep invariant? Induction! Consider all ways to make a new object Consider all ways to modify an existing object What is the difference between constructors and producers? Spring 18 CSCI 2600, K. Kuzmin, A Milanova

39 Benevolent Side Effects in Observers
An implementation of observer IntSet.contains: boolean contains(int x) { int i = data.indexOf(x); if (i == -1) return false; // move-to front optimization // speeds up repeated membership tests Integer y = data.elementAt(0); data.set(0,x); data.set(i,y); return true; } Mutates rep (even though it does not change abstract value), must show rep invariant still holds! Other reasons too! If there is an accidental mutation, we’ll catch it when trying to prove that the rep invariant holds!

40 Ways to Make New Objects
a = constructor b = a.producer a’ = a.mutator a’’ = a.observer c = b.producer b’ = b.mutator b’’ = b.observer Infinitely many objects but limited number of operations! Spring 18 CSCI 2600, K. Kuzmin, A Milanova (based on a slide by Mike Ernst)

41 Induction Base step Inductive step
Prove rep invariant holds on exit of public constructors and for objects emitted by producers Inductive step Assume rep invariant of this object holds on entry of method Then prove rep invariant holds on exit Intuitively: there is no way to make an object, for which the rep invariant does not hold Spring 18 CSCI 2600, K. Kuzmin, A Milanova (based on slide by Mike Ernst)

42 The IntSet ADT /** Overview: An IntSet is a mutable set * of integers. E.g., { x1, x2 , … xn }, {}. * There are no duplicates in the set. */ // effects: makes a new empty IntSet public IntSet() // modifies: this // effects: thispost = thispre U { x } public void add(int x) // effects: thispost = thispre - { x } public void remove(int x) // returns: (x in this) public boolean contains(int x) // reruns: cardinality of this public int size()

43 Implementation of IntSet
class IntSet { // Rep invariant: // data has no nulls and no duplicates private List<Integer> data; public IntSet() { data = new ArrayList<Integer>(); } public void add(int x) { if (!contains(x)) data.add(x); public void remove(int x) { data.remove(new Integer(x)); public boolean contains(int x) { return data.contains(x); NOTE: How can we fix it? Spring 18 CSCI 2600, K. Kuzmin, A Milanova

44 Proof. IntSet Satisfies Rep Invariant
Rep invariant: data has no nulls and no duplicates Base case: constructor public IntSet() { data = new ArrayList<Integer>(); } Rep invariant trivially holds Inductive step: for each method Assume rep invariant holds on entry Prove rep invariant holds on exit Spring 18 CSCI 2600, K. Kuzmin, A Milanova

45 Inductive Step, contains
Rep invariant: data has no nulls and no duplicates public boolean contains(int x) { return data.contains(x); } List.contains does not change data, so neither does IntSet.contains Therefore, rep invariant is preserved. Why do we even need to check contains? Spring 18 CSCI 2600, K. Kuzmin, A Milanova

46 contains with Benevolent Side Effects
An implementation of observer IntSet.contains: boolean contains(int x) { int i = data.indexOf(x); if (i == -1) return false; // move-to front optimization // speeds up repeated membership tests Integer y = data.elementAt(0); data.set(0,x); data.set(i,y); return true; } We swapped elements of data at positions i and 0. If there were no duplicates and no nulls on entry, there are no duplicates and no nulls on exit

47 Inductive Step, remove ArrayList.remove has two behaviors
Rep invariant: data has no nulls and no duplicates public void remove(int x) { data.remove(new Integer(x)); } ArrayList.remove has two behaviors Leaves data unchanged Removes an element (Only addition can violate rep invariant) Therefore, rep invariant is preserved Spring 18 CSCI 2600, K. Kuzmin, A Milanova

48 Inductive Step, add Case 1: x in datapre Case 2: x is not in datapre
Rep invariant: data has no nulls and no duplicates public void add(int x) { if (!contains(x)) data.add(x); } Case 1: x in datapre data is unchanged, thus rep invariant is preserved Case 2: x is not in datapre New element is not null or a duplicate, thus rep invariant holds at exit Spring 18 CSCI 2600, K. Kuzmin, A Milanova

49 Reasoning About Rep Invariant
Inductive step must consider all possible changes to the rep! Spring 18 CSCI 2600, K. Kuzmin, A Milanova

50 Aside: Access Modifiers in Java
Access modifiers can be used to restrict the scope of fields methods classes Levels of access control Top level – public or <default> Member level – public, private, protected, <default> (package-private) Spring 18 CSCI 2600, K. Kuzmin

51 Aside: Access Modifiers in Java
A Java source code file must have the same name as its public class Top level modifiers take precedence over member access level modifiers Spring 18 CSCI 2600, K. Kuzmin Image from

52 Aside: Access Modifiers in Java
Use the most restrictive access level. Use private for all methods unless you know exactly why you need to relax this restriction. Be very careful with the <default> (package-private) access level. No explicit modifier! Never use public fields except for constants. Why? Spring 18 CSCI 2600, K. Kuzmin


Download ppt "Abstraction functions, Reasoning About ADTs"

Similar presentations


Ads by Google