Subtype Polymorphism, Subtyping vs

Slides:



Advertisements
Similar presentations
Identity and Equality Based on material by Michael Ernst, University of Washington.
Advertisements

5/17/2015 OO Design: Liskov Substitution Principle 1.
C8: Understanding Inheritance. Intuitive description Intuitive: FLORISTS are SHOPKEEPERS, inheriting various shopkeeper behaviors Tension in OOP languages:
Overview of Java (continue). Announcements You should have access to your repositories and HW0 If you have problems getting HW0, let me know If you’ve.
From Theory to Practice 1 OOP Overview Reminder – some OOD principles from previous lessons: –Class Inheritance vs. Object Composition –Program.
Abstract Classes and Interfaces
1 Inheritance and Polymorphism Chapter 9. 2 Polymorphism, Dynamic Binding and Generic Programming public class Test { public static void main(String[]
1 Abstraction  Identify important aspects and ignore the details  Permeates software development programming languages are abstractions built on hardware.
SWE 619 © Paul Ammann Procedural Abstraction and Design by Contract Paul Ammann Information & Software Engineering SWE 619 Software Construction cs.gmu.edu/~pammann/
Effective C#, Chapter 1: C# Language Elements Last Updated: Fall 2011.
CSSE501 Object-Oriented Development. Some OO Design Principles  Majority principles here come from: Design Principles in Java, Bob Tarr.
More Implications of Inheritance COMP204, Bernhard Pfahringer.
Chapter 3 Inheritance and Polymorphism Goals: 1.Superclasses and subclasses 2.Inheritance Hierarchy 3.Polymorphism 4.Type Compatibility 5.Abstract Classes.
OO as a language for acm l OO phrase l Mental model of key concepts.
Types in programming languages1 What are types, and why do we need them?
Type Abstraction Liskov, Chapter 7. 2 Liskov Substitution Principle In any client code, if the supertype object is substituted by a subtype object, the.
Type Abstraction SWE Spring October 05Kaushik, Ammann Substitution Principle “In any client code, if supertype object is substituted.
Polymorphism Liskov 8. Outline equals() Revisiting Liskov’s mutable vs. not rule Polymorphism Uniform methods for different types “easy” polymorphism.
1 COSC2007 Data Structures II Chapter 9 Class Relationships.
Subtype Polymorphism, Subtyping vs
Parametric Polymorphism and Java Generics. Announcements One day extension on HW5 Because of an error in my HW5 config HW6 out, due November 10 Grades.
Subtype Polymorphism, cont. Parametric Polymorphism and Java Generics.
CSCI-383 Object-Oriented Programming & Design Lecture 24.
Polymorphism SWE 619. Outline equals() Revisiting Liskov’s mutable vs. not rule Polymorphism Uniform methods for different types “easy” polymorphism Element.
Quick Review of OOP Constructs Classes:  Data types for structured data and behavior  fields and methods Objects:  Variables whose data type is a class.
CSSE501 Object-Oriented Development. Chapter 10: Subclasses and Subtypes  In this chapter we will explore the relationships between the two concepts.
Cs2220: Engineering Software Class 12: Substitution Principle Fall 2010 University of Virginia David Evans.
Recitation 7 Godfrey Tan March 21, Administrivia PS6 due Tuesday right after break Final Project descriptions will be handed out Monday after break.
Subtype Polymorphism, Subtyping vs. Subclassing, Liskov Substitution Principle.
Zach Tatlock / Winter 2016 CSE 331 Software Design and Implementation Lecture 12 Subtypes and Subclasses.
Lecture 6:Interfaces and Abstract Classes Michael Hsu CSULA.
Parametric Polymorphism and Java Generics. Today’s Lecture Outline Subtype polymorphism Subtyping vs. subclassing Liskov Substitution Principle (LSP)
CS/ENGRD 2110 SPRING 2016 Lecture 6: Consequence of type, casting; function equals 1.
Lecture 5:Interfaces and Abstract Classes
Polymorphism in Methods
Sixth Lecture ArrayList Abstract Class and Interface
Object-oriented Programming in Java
Inheritance and Polymorphism
Design Principles.
CSE 331 Subtyping slides created by Marty Stepp based on materials by M. Ernst, S. Reges, D. Notkin, R. Mercer, Wikipedia
EECE 310: Software Engineering
Sorry these slides weren’t available last evening!
Programming Language Concepts (CIS 635)
Type Abstraction SWE Spring 2009.
Continuing Chapter 11 Inheritance and Polymorphism
Exam 2 Review.
Parametric Polymorphism and Java Generics
CSE 331 Software Design and Implementation
Chapter 9 Inheritance and Polymorphism
Subtyping Rules David Evans cs205: engineering software BlackBear
Testing, conclusion Based on material by Michael Ernst, University of Washington.
Testing, cont., Equality and Identity
Java Programming Language
Specifications, conclusion. Abstract Data Types (ADTs)
Type Abstraction Liskov, Chapter 7.
Equality, conclusion Based on material by Michael Ernst, University of Washington.
Subtype Polymorphism, Subtyping vs
Building Java Programs
Generic programming in Java
CSE 331 Software Design and Implementation
Java Reasoning About Code
CSE 331 Software Design & Implementation
CSE 331 Software Design & Implementation
EECE 310: Software Engineering
IMPORTANT NOTE Some parts of these section slides deal with null ints. This was a mistake, as primitives cannot be null. These issues have been corrected.
Chapter 14 Abstract Classes and Interfaces
Chapter 11 Inheritance and Polymorphism Part 2
Lecture 13: Subtyping Rules Killer Bear Climber
Type Abstraction SWE Spring 2013.
Software Specifications
Presentation transcript:

Subtype Polymorphism, Subtyping vs Subtype Polymorphism, Subtyping vs. Subclassing, Liskov Substitution Principle

Announcements Generics will not be on Exam 2 HW5 is due today, March 26, 2018 at 11:59:59 pm Exam 2 is next Thursday, March 29, 2018. Practice exam has been posted. Solutions will be posted tonight/tomorrow morning Generics will not be on Exam 2

Outline Subtype polymorphism Subtyping vs. subclassing Liskov Substitution Principle (LSP) Function subtyping Java subtyping Composition: an alternative to inheritance Spring 18 CSCI 2600, K. Kuzmin, A Milanova

Intuition: Type Signature is a Specification Type signature is a contract too E.g., double f(String s, int i) {…} Precondition: arguments are a String and an int Postcondition: result is a double We need reasoning about behavior and effects, so we added requires, effects, etc. Spring 18 CSCI 2600, K. Kuzmin, A Milanova

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: A f(B) is a function subtype of C f’(D) iff A is a subtype of C and B is a supertype of D Guarantees substitutability (at the level of signature) Spring 18 CSCI 2600, K. Kuzmin, A Milanova

Type Signature of Substituting Method is Stronger Method parameters (inputs): Parameter types of A.m may be replaced by supertypes in subclass B.m. ”contravariance” E.g., A.m(String p) and B.m(Object p) B.m places no extra requirements on the client! E.g., client: A a; … a.m(q). Client knows to provide q a String. Thus, client code will work fine with B.m(Object p), which asks for less: an Object, and clearly, every String is an Object Java does not allow change of parameter types in an overriding method. More on Java overriding shortly B Think of parameters and return as part of the method specification (not including behavior). As we discussed some time ago.

Type Signature of Substituting Method is Stronger Method returns (results): Return type of A.m may be replaced by subype in subclass B.m. “covariance” E.g., Object A.m() and String B.m() B.m does not violate expectations of the client! E.g., client: A a; … Object o = a.m(). Client expects an Object. Thus, String will work fine No new exceptions. Existing exceptions can be replaced by subtypes Java does allow a subtype return type in an overriding method! B Think of return type as part of the postcondition of the spec.

Properties Class from the JDK Properties stores String key-value pairs. It extends Hashtable so Properties is a Java subtype of Hashtable. What’s the problem? class Hashtable { // modifies: this // effects: associates value with key public void put(Object key, Object value); // returns: value associated with key public Object get(Object key); } class Properties extends Hashtable { // simplified // effects: associates String value with String key public void put(String key, String value) { super.put(key, value); public String get(String key) { return (String) super.get(key);

Exercise class Hashtable { public void put(Object key, Object value); public Object get(Object key); } class Properties extends Hashtable { public void put(String key, String value); public String get(String key); Spring 18 CSCI 2600, K. Kuzmin, A Milanova (based on example by Michael Ernst)

Exercise Assume Z subtype of Y, Y subtype of X class A: X m(Y, String) Which ones are function subtypes of A.m Y m(X, Object) Object m(X, Object) Y m(Z, String) Z m(X, String) Spring 18 CSCI 2600, K. Kuzmin, A Milanova

Exercise class Product { Product recommend(Product p); } Which one is a function subtype of Product.recommend? class SaleProduct extends Product { Product recommend(SaleProduct p); SaleProduct recommend(Product p); Product recommend(Object p); Product recommend(Product p) throws NoSaleException; Spring 18 CSCI 2600, K. Kuzmin, A Milanova (based on example by Michael Ernst)

Reasoning about Specs Function subtyping reasons with type signatures Remember, type signature is a specification Precondition: requires arguments of given type Postcondition: promises result of given type Compiler can check function subtyping Specifications (such as PoS specifications) add behavior and effects Precondition: stated by requires clause Postcondition: stated by modifies, effects, returns and throws clauses Reasoning about specification strength is reasoning about “behavioral subtyping”

Reasoning about Specs Behavioral subtyping generalizes function subtyping B.m is a “behavioral subtype of/stronger than” A.m B.m has weaker precondition than A.m This is contravariance Just like requirement of function subtyping: “B.m’s parameter is a supertype of A.m’s parameter” B.m has stronger postcondition than A.m This is covariance Just like “B.m’s return is a subtype of A.m’s return” These 2 conditions guarantee B.m’s spec is stronger than A.m’s spec, and B.m is substitutable for A.m

Outline Subtype polymorphism Subtyping vs. subclassing Liskov Substitution Principle (LSP) Function subtyping Java subtyping Composition: an alternative to inheritance Spring 18 CSCI 2600, K. Kuzmin, A Milanova

Java Subtypes Java types are defined by classes, interfaces, primitives Java subtyping stems from declarations B extends A B implements A In a Java subtype, a “substituting” method is an overriding method Has same parameter types Has compatible (same or subtype) return type Has no additional declared exceptions Stricter rule than what function subtyping expects. Allows for covariant return, but does not allow for contravariant arguments because that would not interact well with Subtype polymorphism! Spring 18 CSCI 2600, K. Kuzmin, A Milanova (based on slide by Mike Ernst)

Overloading vs. Overriding If a method has same name, but different parameter types, it overloads not overrides class Hashtable { public void put(Object key, Object value); public Object get(Object key); } class Properties extends Hashtable { public void put(String key, String value); public String get(String key); Now Properties has 4 methods: void put(Object key, Object key) // inherited from Hashtable Object get(Object key) // inherited from Hashtable void put(String key, String key) // overloaded put String get(String key) // overloaded get Suppose we have Properties p = … String s1, s2; Integer i1, i2; p.put(s1,s2); // Which put is called here? put(String s1, String s2), it is a better match! p.put(s1,i2); // put(Object,Object)! overload Hashtable’s put and get Spring 18 CSCI 2600, K. Kuzmin, A Milanova

Overloading vs. Overriding A method family contains multiple implementations of same name + parameter types (but not 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 within the method family runs, is determined at runtime based on the runtime type of the receiver Spring 18 CSCI 2600, K. Kuzmin, A Milanova (based on slides by Mike Ernst)

Remember Duration class Object { public boolean equals(Object o); } class Duration { public boolean equals(Duration d); Duration d1 = new Duration(10,5); Duration d2 = new Duration(10,5); System.out.println(d1.equals(d2)); // Compiler choses family equals(Duration d) Two method families. Spring 18 CSCI 2600, K. Kuzmin, A Milanova

Remember Duration class Object { public boolean equals(Object o); } class Duration { public boolean equals(Duration d); Object d1 = new Duration(10,5); Duration d2 = new Duration(10,5); System.out.println(d1.equals(d2)); // At compile-time: equals(Object o) // At runtime: Duration.equals(Object o)

Remember Duration class Object { public boolean equals(Object o); } class Duration { public boolean equals(Duration d); Object d1 = new Duration(10,5); Object d2 = new Duration(10,5); System.out.println(d1.equals(d2)); // Compiler choses equals(Object o) // At runtime: Duration.equals(Object o)

Remember Duration class Object { public boolean equals(Object o); } class Duration { public boolean equals(Duration d); Duration d1 = new Duration(10,5); Object d2 = new Duration(10,5); System.out.println(d1.equals(d2)); // Compiler choses equals(Object o) // At runtime: Duration.equals(Object o)

Exercise class Y extends X { … } class A { X m(Object o) { … } } class B extends A { X m(Z z) { … } class C extends B { Y m(Z z) { … } A a = new B(); Object o = new Object(); // Which m is called? X x = a.m(o); A a = new C(); Object o = new Z(); What are the method families? Spring 18 CSCI 2600, K. Kuzmin, A Milanova

Exercise class Y extends X { … } class W extends Z { … } class A { X m(Z z) { … } } class B extends A { X m(W w) { … } class C extends B { Y m(W w) { … } A a = new B(); W w = new W(); // Which m is called? X x = a.m(w); B b = new C(); X x = b.m(w); Spring 18 CSCI 2600, K. Kuzmin, A Milanova

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() This is type safety. It rules out a huge class of bugs! Compare with C++!

Subclassing is Difficult Before: class A { private int c=0; void inc1() { c++; } void inc2() { c++; } } class B extends A { @Override void inc2() { inc1(); After a tiny change: class A { private int c=0; void inc1() { inc2(); } void inc2() { c++; } } class B extends A { @Override void inc2() { inc1(); Spring 18 CSCI 2600, K. Kuzmin, A Milanova

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 Spring 18 CSCI 2600, K. Kuzmin, A Milanova

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; } Spring 18 CSCI 2600, K. Kuzmin, A Milanova (based on example by Michael Ernst)

Subclassing is Difficult InstrumetedHashSet s=new InstrumentedHashSet(); System.out.println(s.getAddCount()); // 0 s.addAll(Arrays.asList(“One”,”Two”)); System.out.println(s.getAddCount()); // Prints? HashSet … this.add(o);… add(Object o) addAll(Collection c) addCount++; super.add(o); InstrumentedHashSet addCount += c.size(); super.addAll(c); add(Object o) addAll(Collection c) Spring 18 CSCI 2600, K. Kuzmin, A Milanova

The Yo-yo Problem 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!

Java Subtyping with Interfaces Why Set and not HashSet? 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 A nice useful trick. “implements Set” allows our InstrumentedHashSet to be treated as a Set. On the other hand it does not extend anything. It reuses HashSet through Composition. Spring 18 CSCI 2600, K. Kuzmin, A Milanova (based on example by Michael Ernst)

Java Subtyping with Interfaces Which I call 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! Caveat: Java 8’s default methods complicate this! Facilitates composition and wrapper classes as in the InstrumentedHashSet example Spring 18 CSCI 2600, K. Kuzmin, A Milanova

Java Subtyping with Interfaces In JDK and 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 Equality lecture) Inheritance is overrated as a means for code reuse. Composition is better.

Why prefer implements A over extends A 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

Outline Subtype polymorphism Subtyping vs. subclassing Liskov Substitution Principle (LSP) Function subtyping Java subtypes Composition: an alternative to inheritance Spring 18 CSCI 2600, K. Kuzmin, A Milanova

Composition Properties extending Hashtable was problematic, thus, we cannot subclass. An alternative solution? InstrumentedHashSet extending HashSet was a bad idea too. An alternative? Box was not a true subtype of BallContainer. Cannot subclass. Composition! Spring 18 CSCI 2600, K. Kuzmin, A Milanova

Properties Wrapper class The delegate 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); Spring 18 CSCI 2600, K. Kuzmin, A Milanova

InstrumentedHashSet The delegate 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; } Spring 18 CSCI 2600, K. Kuzmin, A Milanova

Box The delegate 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); … Spring 18 CSCI 2600, K. Kuzmin, A Milanova

Composition Implementation reuse without inheritance More common than implementation reuse through inheritance (subclassing)! Easy to reason about Can works around badly-designed classes Disadvantages? Spring 18 CSCI 2600, K. Kuzmin, A Milanova

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 Spring 18 CSCI 2600, K. Kuzmin, A Milanova (based on slide by Michael Ernst)

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 A nice useful trick. “implements Set” allows our InstrumentedHashSet to be treated as a Set. On the other hand it does not extend anything. It reuses HashSet through Composition. I don’t need to do addCount += c.size() here. Why?