Download presentation
Presentation is loading. Please wait.
Published byAubrie Ray Modified over 8 years ago
1
Parametric Polymorphism and Java Generics
2
Today’s Lecture Outline Subtype polymorphism Subtyping vs. subclassing Liskov Substitution Principle (LSP) Function subtyping Java subtyping Composition: an alternative to inheritance Fall 15 CSCI 2600, A Milanova 2
3
Liskov Substitution Principle Java subtypes (realized with extends, implements ) must be true subtypes Java subtypes that are not true subtypes are dangerous and confusing When B is a Java subtype of A, ensure 1. B, does not remove methods from A 2. A substituting method B.m has stronger specification than method A.m which it substitutes Guarantees substitutability of class B for A 3
4
Function Subtyping In programming languages function subtyping deals with substitutability of functions Question: under what conditions on the parameter and return types A,B,C and D, is function A f(B) substitutable for C f(D) Reasons at the level of the type signature Rule: If A is a subtype of C and B is a supertype of D then A f(B) is a function subtype of C f(D) Guarantees substitutability of A f(B) for C f(D)! Fall 15 CSCI 2600, A Milanova 4
5
Overloading vs. Overriding in Java A method family contains multiple implementations of same name + parameter types sub-signature (no return type) Which method family is determined at compile time based on compile-time types E.g., family put(Object key, Object value) or family put(String key, String value) Which implementation from the method family runs, is determined at runtime based on the runtime type of the receiver Fall 15 CSCI 2600, A Milanova (based on slides by Mike Ernst) 5
6
Java Subtyping Guarantees A variable’s runtime type (i.e., the class of its runtime object) is a Java subtype of the variable’s declared class (Not true in C++!) Object o = new Date(); // OK Date d = new Object(); // Compile-time error Thus, objects always have implementations of the method specified at the call site Client: B b; … b.m() // Runtime object has m() If all subtypes are true subtypes, spec of runtime target m() is stronger than spec of B.m() 6
7
Subclassing is Difficult Before: class A { private int c=0; void inc1() { c++; } void inc2() { c++; } } class B extends A { @Override void inc2() { inc1(); } Fall 15 CSCI 2600, A Milanova 7 After a tiny change: class A { private int c=0; void inc1() { inc2(); } void inc2() { c++; } } class B extends A { @Override void inc2() { inc1(); }
8
Fragile Base Class Problem Previous slide showed an example of the Fragile Base Class Problem Fragile Base Class Problem happens when seemingly innocuous changes in the superclass break the subclass Fall 15 CSCI 2600, A Milanova 8
9
Subclassing is Difficult A set that counts the number of attempted additions: class InstrumentedHashSet extends HashSet { private int addCount = 0; public InstrumentedHashSet(Collection c) { super(c); } public boolean add(Object o) { addCount++; return super.add(o); } public boolean addAll(Collection c) { addCount += c.size(); return super.addAll(c); } public int getAddCount() { return addCount; } } Fall 15 CSCI 2600, A Milanova (based on example by Michael Ernst) 9
10
Subclassing is Difficult InstrumentedHashSet is a true subtype of HashSet. But… Something goes quite wrong here class InstrumentedHashSet extends HashSet { private int addCount = 0; public InstrumentedHashSet(Collection c) { super(c); } public boolean add(Object o) { addCount++; return super.add(o); } public boolean addAll(Collection c) { addCount += c.size(); return super.addAll(c); } public int getAddCount() { return addCount; } } 10
11
Subclassing is Difficult InstrumentedHashSet s=new InstrumentedHashSet(); System.out.println(s.getAddCount()); // 0 s.addAll(Arrays.asList(“One”,”Two”)); System.out.println(s.getAddCount()); // Prints? Fall 15 CSCI 2600, A Milanova 11 HashSet add(Object o) addAll(Collection c) InstrumentedHashSet add(Object o) addAll(Collection c) addCount += c.size(); super.addAll(c); … this.add(o);… addCount++; super.add(o);
12
this.add(o) in superclass HashSet calls InstrumentedHashSet. add ! Callback. Example of the yo-yo problem. Call chain “yo-yos” from subclass to superclass back to subclass InstrumentedHashSet.addAll calls HashSet.addAll calls InstrumentedHashSet.add Behavior of HashSet.addAll depends on subclass InstrumentedHashSet ! 12 The Yo-yo Problem
13
Java Subtyping with Interfaces class InstrumentedHashSet implements Set { private final Set s = new HashSet(); private int addCount = 0; public InstrumentedHashSet(Collection c) { this.addAll(c); } public boolean add(Object o) { addCount++; return s.add(o); } public boolean addAll(Collection c) { addCount += c.size(); return s.addAll(c); } public int getAddCount() { return addCount; } // … Must add all methods specified by Set } Fall 15 CSCI 2600, A Milanova (based on example by Michael Ernst) 13
14
Java Subtyping with Interfaces Which is also called interface inheritance Client codes against type signature of interface methods, not concrete implementations Behavioral specification of an interface method often unconstraint: often just true => false. Any (later) implementation is stronger! Facilitates composition and wrapper classes as in the InstrumentedHashSet example Fall 15 CSCI 2600, A Milanova 14
15
Java Subtyping with Interfaces In JDK and the Android SDK Implement multiple interfaces, extend single abstract superclass (very common!) Abstract classes minimize number of methods new implementations must provide Abstract classes facilitate new implementations Using abstract classes is optional, so they don’t limit freedom Extending a concrete class is rare and often problematic (e.g., Properties, Timestamp, which we saw in the Equality lecture) 15
16
A class has exactly one superclass. In contrast, a class may implement multiple interfaces. An interface may extend multiple interfaces Interface inheritance gets all the benefit of subtype polymorphism And avoids the pitfalls of subclass inheritance, such as the fragile base class problem, etc. Multiple interfaces, single abstract superclass gets most of the benefit 16 Why prefer implements A over extends A ?
17
Outline Subtype polymorphism Subtyping vs. subclassing Liskov Substitution Principle (LSP) Function subtyping Java subtypes Composition: an alternative to inheritance Fall 15 CSCI 2600, A Milanova 17
18
Composition Properties is not a true subtype of Hashtable. Thus, cannot subclass. An alternative solution? Subclassing is a bad idea for the InstrumentedHashSet too. An alternative? Box is not a true subtype of BallContainer. Cannot subclass. Composition! Fall 15 CSCI 2600, A Milanova 18
19
Properties class Properties { // simplified private Hashtable ht = new Hashtable(); // modifies: this // effects: associates value with key public void setProperty(String key,String value) { ht.put(key,value); } // returns: value associated with key public void getProperty(String key) { return (String) ht.get(key); } Fall 15 CSCI 2600, A Milanova 19 The delegate Wrapper class
20
class InstrumentedHashSet { private final Set s = new HashSet(); private int addCount = 0; public InstrumentedHashSet(Collection c) { s.addAll(c); } public boolean add(Object o) { addCount++; return s.add(o); } public boolean addAll(Collection c) { addCount += c.size(); return s.addAll(c); } public int getAddCount() { return addCount; } } Fall 15 CSCI 2600, A Milanova 20 InstrumentedHashSet The delegate
21
class Box { private BallContainer ballContainer; private double maxVolume; public Box(double maxVolume) { this.ballContainer = new BallContainer(); this.maxVolume = maxVolume; } public boolean add(Ball b) { if (b.getVolume() + ballContainer.getVolume() > maxVolume) return false; else return ballContainer.add(b); } … Fall 15 CSCI 2600, A Milanova 21 Box The delegate
22
Composition Implementation reuse without inheritance More common than implementation reuse through inheritance (subclassing)! Easy to reason about Can work around badly designed classes Disadvantages Adds level of indirection Tedious to write Does not preserve subtyping Fall 15 CSCI 2600, A Milanova 22
23
Composition Does not Preserve Subtyping InstrumentedHashSet is not a Set anymore So can’t substitute it It may be a true subtype of Set ! But Java doesn’t know that That nice trick with interfaces to the rescue Declare that the class implements interface Set Requires that such interface exists Fall 15 CSCI 2600, A Milanova (based on slide by Michael Ernst) 23
24
Nice Trick with Interfaces class InstrumentedHashSet implements Set { private final Set s = new HashSet(); private int addCount = 0; public InstrumentedHashSet(Collection c) { this.addAll(c); } public boolean add(Object o) { addCount++; return s.add(o); } public boolean addAll(Collection c) { addCount += c.size(); return s.addAll(c); } public int getAddCount() { return addCount; } // … Must add all methods specified by Set } 24
25
Today’s Lecture Outline Parametric polymorphism Java generics Declaring and instantiating generics Bounded types: restricting instantiations Generics and subtyping. Wildcards Type erasure Java arrays Fall 15 CSCI 2600, A Milanova 25
26
Polymorphism Subtype polymorphism What we discussed… Code can use a subclass B where a superclass A is expected E.g., Code A a; … a.m() is “polymorphic”, because a can be of many different types at runtime: it can be an A object or a B object. Code works with A and with B (with some caveats!) Standard in object-oriented languages Fall 15 CSCI 2600, A Milanova 26
27
Polymorphism Parametric polymorphism Code takes a type as a parameter Implicit parametric polymorphism Explicit parametric polymorphism Standard in functional programming languages Overloading typically referred to as “ad-hoc” polymorphism Fall 15 CSCI 2600, A Milanova 27
28
Implicit Parametric Polymorphism There are no explicit type parameter(s). Code is “polymorphic” because it works with many different types. E.g.: def intersect(sequence1, sequence2): result = [ ] for x in sequence1: if x in sequence2: result.append(x) return result As long as sequence1 and sequence2 are of some iterable type, intersect works! 28 Fall 15 CSCI 2600, A Milanova
29
Implicit Parametric Polymorphism In Python, Lisp, Scheme, others languages There is no explicit type parameter(s); the code works with many different types Usually, there is a single copy of the code, and all type checking is delayed until runtime If the arguments are of type as expected by the code, code works If not, code issues a type error at runtime Fall 15 CSCI 2600, A Milanova 29
30
Explicit Parametric Polymorphism In C++, Java, Ada, Clu There are explicit type parameter(s) Explicit parametric polymorphism is also known as genericity E.g. in C++ we have templates: template class list_node { list_node * prev; … } 30 template class list { list_node header; … }
31
Explicit Parametric Polymorphism Instantiating classes from previous slide with int : typedef list_node int_list_node; typedef list int_list; Usually templates are implemented by creating multiple copies of the generic code, one for each concrete type argument, then compiling Problem: if you instantiate with the “wrong” type argument, C++ compiler gives us long, cryptic error messages referring to the generic (templated) code in the STL :) 31
32
Explicit Parametric Polymorphism Java generics work differently from C++ templates: more type checking on generic code OO languages usually have both: subtype polymorphism (through inheritance: A extends B or A implements B), and explicit parametric polymorphism, referred to as generics or templates Java didn’t have generics until Java 5 (2004)! 32
33
Using Java Generics List list = new ArrayList (); AType is the type argument. We instantiated generic (templated) class ArrayList with concrete type argument AType List names = new ArrayList (); names.add(“Ana”); names.add(“Katarina”); String s = names.get(0); // what happens here? Point p = names.get(0); // what happens here? Point p = (Point) names.get(0); // what happens? Fall 15 CSCI 2600, A Milanova (modified from an example by Michael Ernst) 33
34
Defining a Generic Class class MySet { // rep invariant: non-null, // contains no duplicates List theRep; T lastLookedUp; } Fall 15 CSCI 2600, A Milanova (example by Michael Ernst) 34 Declaration of type parameter Use of type parameter
35
Defining a Generic Class // generic (templated, parameterized) class public class Name { Convention: TypeVar is 1-letter name such as T for Type, E for Element, N for Number, K for Key, V for Value Class code refers to the type parameter E.g., E To instantiate a generic class, client supplies type arguments E.g., String as in List name; Think of it as invoking a “constructor” for the generic class Fall 15 CSCI 2600, A Milanova (example by Michael Ernst) 35
36
Example: a Generic Interface // Represents a list of values public interface List { public void add(E value); public void add(int index, E value); public E get(int index); public int indexOf(E value); public boolean isEmpty(); public void remove(int index); public void set(int index, E value); public int size(); } public class ArrayList implements List { public class LinkedList implements List { Fall 15 CSCI 2600, A Milanova (example by Michael Ernst) 36
37
Generics Clarify Your Code Without generics This is known as “pseudo-generic containers” interface Map { Object put(Object key, Object value); Object get(Object key); } Client code: Map nodes2neighbors = new HashMap(); String key = … nodes2neigbors.put(key,value); HashSet neighbors = (HashSet) nodes2neighbors.get(key); 37 Casts in client code. Clumsy. If client mistakenly puts non-HashSet value in map, ClassCastException at this point.
38
Generics Clarify Your Code With generics interface Map { V put(K key, V value); V get(K key); } Client code: Map > nodes2neighbors = new HashMap >(); String key = … nodes2neigbors.put(key,value); HashSet neighbors = nodes2neighbors.get(key); 38 No casts. Compile-time checks prevent client from putting non-HashSet value. Somewhat clumsy, verbose instantiations.
39
Today’s Lecture Outline Parametric polymorphism Java generics Declaring and instantiating generics Bounded types: restricting instantiations Generics and subtyping. Wildcards Type erasure Java arrays Fall 15 CSCI 2600, A Milanova 39
40
Bounded Types Restrict Instantiation by Client interface MyList1 { … } MyList1 can be instantiated with any type. Same as interface MyList1 { … } interface MyList2 { … } MyList2 can be instantiated only with type arguments that are Number or subtype of Number MyList1 // OK MyList2 // what happens here? Fall 15 CSCI 2600, A Milanova (example by Michael Ernst) 40 Upper bound on type argument
41
Why Bounded Types? Generic code can perform operations permitted by the bound class MyList1 void m(E arg) { arg.intValue();//compile-time error; Object //does not have intValue() } } class MyList2 void m(E arg) { arg.intValue();//OK. Number has intValue() } } Fall 15 CSCI 2600, A Milanova (modified from example by Michael Ernst) 41
42
Another Example public class Graph implements Iterable private final Map > node2neighbors; public Graph(Set nodes, Set > edges) { … } public interface Path > extends Iterable, Comparable > { public Iterator iterator(); … } Fall 15 CSCI 2600, A Milanova (examples by Michael Ernst) 42
43
Bounded Type Parameters An upper bound, type argument can be SuperType or any of its subtypes A lower bound, type argument can be SubType or any of its supertypes Fall 15 CSCI 2600, A Milanova (modified from slide by Michael Ernst) 43
44
Exercise Given this hierarchy with X, Y and Z: What are valid instantiations of generics class A { … } ? Fall 15 CSCI 2600, A Milanova 44 X Y Z
45
Declaring a Generic Method class MyUtils { T sumList(Collection l) { … } Fall 15 CSCI 2600, A Milanova (modified from example by Michael Ernst) 45 Declaration of type parameter Uses of type parameter
46
Generic Method Example: Sorting public static > void sort(List list) { // use of get & T.compareTo // T e1 = l.get(…); // T e2 = l.get(…); // e1.compareTo(e2); … } Fall 15 CSCI 2600, A Milanova (modified from example by Michael Ernst) 46 We can use T.compareTo because T is bounded by Comparable !
47
Another Generic Method Example public class Collections { … public static void copy(List dst, List src) { for (T t : src) { dst.add(t); } Fall 15 CSCI 2600, A Milanova (modified from example by Michael Ernst) 47 When you want to make a single (often static) method generic in a class, precede its return type by type parameter(s).
48
More Bounded Type Examples > T max(Collection c); void copy(List dst, List src); ( actually, must use wildcard ? --- more on this later: void copy(List dst, List src); ) > void sort(List list) (same, must use ? with super: ) Fall 15 CSCI 2600, A Milanova (modified from a slide by Michael Ernst) 48
49
Today’s Lecture Outline Parametric polymorphism Java generics Declaring and instantiating generics Bounded types: restricting instantiations Generics and subtyping. Wildcards Type erasure Java arrays Review questions Fall 15 CSCI 2600, A Milanova 49
50
Java Wildcards public static void copy(List dst, List src) > void sort(List list) Fall 15 CSCI 2600, A Milanova (modified from a slide by Michael Ernst) 50
51
Generics and Subtyping Integer is a subtype of Number Is List a subtype of List ? Fall 15 CSCI 2600, A Milanova 51 Number Integer List ?
52
Use Function Subtyping Rules to Find Out! interface List { boolean add(Number elt); Number get(int index); } interface List { boolean add(Integer elt); Integer get(int index); } Function subtyping: subtype must have supertype parameters and subtype return! 52 List ?
53
What is the Subtyping Relationship Between List and List Java subtyping is invariant with respect to generics: if A ≠ B, then C has no subtyping relationship with C Thus, List and List are unrelated through subtyping! 53 List
54
Immutable Lists interface ImmutableList { Number get(int index); } interface ImmutableList { Integer get(int index); } 54 ImmutableList ? Fall 15 CSCI 2600, A Milanova (example due to Michael Ernst)
55
Write-only Lists interface WriteOnlyList { boolean add(Number elt); } interface WriteOnlyList { boolean add(Integer elt); } Is WriteOnlyList subtype of WriteOnlyList NO! Is WriteOnlyList subtype of WriteOnlyList YES! 55 Fall 15 CSCI 2600, A Milanova (example due to Michael Ernst)
56
Getting Stuff Out of WriteList interface WriteList { boolean add(Number elt); Number get(int index); } interface WriteList { boolean add(Integer elt); Object get(int index); } Is WriteList subtype of WriteList YES! Contravariant subtyping: because the subtyping relationship between the composites (WriteList is subtype of WriteList ) is the opposite of the subtyping relationship between their type arguments (Integer is subtype of Number) 56
57
Invariance is Restrictive (Because it Disallows Subtyping) Java solution: wildcards interface Set { // Adds all elements in c to this set // if they are not already present. void addAll(Set c); void addAll(Collection c); } 57 Not good. Can’t have Set s; List l; s.addAll(l); // List & Set unrelated Not good either. Can’t have Set s; List l; s.addAll(l); This is because of invariance: List is a subtype of Collection but Collection is not a subtype of Collection ! Solution: wildcards. ? Is the wildcard.
58
Java Wildcards A wildcard is essentially an anonymous type variable Use ? if you’d use a type variable exactly once ? appears at use sites of the generic type, not at declaration sites Purpose of the wildcard is to make a library more flexible and easier to use by allowing limited subtyping 58
59
Using Wildcards class HashSet implements Set { void addAll(Collection c) { // What does this give us about c? // i.e., what can code assume about c? // What operations can code invoke on c? } There is also Intuitively, why makes sense here? Fall 15 CSCI 2600, A Milanova (based on slide due to Michael Ernst) 59 This is use of the parameter type E
60
Legal Operations on Wildcards Object o; Number n; Integer i; PositiveInteger p; List lei; First, which of these is legal? lei = new ArrayList (); Fall 15 CSCI 2600, A Milanova (slide due to Michael Ernst) 60 Which of these is legal? lei.add(o); lei.add(n); lei.add(i); lei.add(p); lei.add(null); o = lei.get(0); n = lei.get(0); i = lei.get(0); p = lei.get(0);
61
Legal Operations on Wildcards Object o; Number n; Integer i; PositiveInteger p; List lsi; First, which of these is legal? lsi = new ArrayList (); Fall 15 CSCI 2600, A Milanova (slide due to Michael Ernst) 61 Which of these is legal? lsi.add(o); lsi.add(n); lsi.add(i); lsi.add(p); lsi.add(null); o = lsi.get(0); n = lsi.get(0); i = lsi.get(0); p = lsi.get(0);
62
How to Use Wildcards PECS: Producer Extends, Consumer Super Use when you get (read) values from a producer Use when you add (write) values into a consumer E.g.: void copy(List dst, List src) Use neither, just, if both add and get Fall 15 CSCI 2600, A Milanova (based on slide by Michael Ernst) 62
63
Wildcards allow Subtyping for Generics Fall 15 CSCI 2600, A Milanova 63 Object Number Integer List ArrayList List
64
Today’s Lecture Outline Parametric polymorphism Java generics Declaring and instantiating generics Bounded types: restricting instantiations Generics and subtyping. Wildcards (briefly) Type erasure Arrays Review problems Fall 15 CSCI 2600, A Milanova 64
65
Type Erasure All type arguments become Object when compiled Reason: backward compatibility with old bytecode At runtime all generic instantiations have same type List lst1 = new ArrayList (); List lst2 = new ArrayList (); lst1.getClass() == lst2.getClass() // true Cannot use instanceof to find type argument Collection cs = new ArrayList (); if (cs instanceof Collection ) { // compile-time error Must use equals() on elements of generic type 65
66
Equals for a Generic Class class Node { … @Override public boolean equals(Object obj) { if (!(obj instanceof Node )) return false; Node n = (Node ) obj; return this.data().equals(n.data()); } Fall 15 CSCI 2600, A Milanova (modified from slide by Michael Ernst) 66 At runtime, JVM has no knowledge of type argument. Node is same as Node. Instanceof is a compile- time error.
67
Equals for a Generic Class class Node { … @Override public boolean equals(Object obj) { if (!(obj instanceof Node )) { return false; Node n = (Node ) obj; return this.data().equals(n.data()); } Fall 15 CSCI 2600, A Milanova (modified from slide by Michael Ernst) 67 Same here. JVM has no knowledge of type argument. Node will cast to Node. Casting results in a compile-time warning, but not error.
68
Today’s Lecture Outline Parametric polymorphism Java generics Declaring and instantiating generics Bounded types: restricting instantiations Generics and subtyping. Wildcards (briefly) Type erasure Arrays Review questions Fall 15 CSCI 2600, A Milanova 68
69
Arrays and Subtyping Integer is subtype of Number Is Integer[] a subtype of Number[] Use our subtyping rules to find out (Just like with List and List ) Again, the answer is NO! Different answer in Java: in Java Integer[] is a Java subtype Number[] ! The Java subtype is not a true subtype! Known as “problem with Java’s covariant arrays” 69 Number Integer Number[] Integer[] ?
70
Integer[] is a Java subtype of Number[] Number n;ia = na; //what Number[] na;// happens here? Integer i;Double d = 3.14; Integer[] ia;na = ia; //what? na[0] = n;na[2] = d; //? na[1] = i;i = ia[2]; n = na[0]; i = na[1]; //what happens? ia[0] = n; //what happens? ia[1] = i; n = ia[0]; i = ia[1]; 70
71
Today’s Lecture Outline Parametric polymorphism Java generics Declaring and instantiating generics Bounded types: restricting instantiations Generics and subtyping. Wildcards (briefly) Type erasure Arrays Review questions Fall 15 CSCI 2600, A Milanova 71
72
Prints What? Object d1 = new Duration(10,5); Object d2 = null; System.out.println(d1.equals(d2)); Fall 15 CSCI 2600, A Milanova 72
73
True or False? Question 2. If there are non-null reference values x, y and z such that x.equals(y) returns false, y.equals(z) returns true and x.equals(z) returns true, then equals is not transitive. Question 3. The consistency property requires that for every non-null x and y, such that x.equals(y) is false, x.hashCode() != y.hashCode(). Question 4. Integer f(String) is a function subtype of Number f(Object). 73
74
CFG and Def-use Pairs 74 s=0; x=0; x<y x+y<10 5.s=s+x+y6.s=s+x-y; return s; True False True False “Merge” node x=x+3; y=y+2; int f(int y) { 1. int s = 0; int x = 0; 2. while (x<y) { 3. x = x+3; y = y+2; 4. if (x+y<10) 5. s = s+x+y; else 6. s = s+x-y; 7. // end-if } // end-while 8. return s; } Is it possible to cover def-use pair (6,5)?
75
True of False Specification tests is just another name for black-box tests. Fall 15 CSCI 2600, A Milanova 75
76
Exceptions void m() {... try { String s = new String("car"); String sub = s.substring(4); // IOOBE } catch (RuntimeException e) { e.printStackTrace(); } // the rest of m } a) catch block catches exception then m proceeds b) exception terminates m and propagates to the caller of m. Fall 15 CSCI 2600, A Milanova 76
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.