CSCE 314: Programming Languages Dr. Dylan Shell

Slides:



Advertisements
Similar presentations
Object Oriented Programming with Java
Advertisements

OO Programming in Java Objectives for today: Overriding the toString() method Polymorphism & Dynamic Binding Interfaces Packages and Class Path.
SUMMARY: abstract classes and interfaces 1 Make a class abstract so instances of it cannot be created. Make a method abstract so it must be overridden.
METHOD OVERRIDING 1.Sub class can override the methods defined by the super class. 2.Overridden Methods in the sub classes should have same name, same.
Module 8 “Polymorphism and Inheritance”. Outline Understanding Inheritance Inheritance Diagrams Constructors in Derived Classes Type Compatibility Polymorphism.
Generic programming in Java
Big Java by Cay Horstmann Copyright © 2009 by John Wiley & Sons. All rights reserved. Chapter 17 – Generic Programming.
Copyright © 2014 by John Wiley & Sons. All rights reserved.1 Chapter 18 – Generic Classes.
ACM/JETT Workshop - August 4-5, :Inheritance and Interfaces.
Java Generics.
© 2006 Pearson Addison-Wesley. All rights reserved9 A-1 Chapter 9 Advanced Java Topics.
1 Chapter 6 Inheritance, Interfaces, and Abstract Classes.
1 Evan Korth New York University Inheritance and Polymorphism Professor Evan Korth New York University.
1 Inheritance and Polymorphism. 2 Motivations Suppose you will define classes to model circles, rectangles, and triangles. These classes have many common.
1 Evan Korth New York University Inheritance and Polymorphism Professor Evan Korth New York University.
Chapter 10 Classes Continued
Generic Java 21/ What is generics? To be able to assign type variables to a class These variables are not bound to any specific type until the.
Principles of Computer Programming (using Java) Review Haidong Xue Summer 2011, at GSU.
Appendix A.2: Review of Java and Object-Oriented Programming: Part 2 “For the object-oriented project, remember that the primary unit of decomposition.
“is a”  Define a new class DerivedClass which extends BaseClass class BaseClass { // class contents } class DerivedClass : BaseClass { // class.
Java Implementation: Part 3 Software Construction Lecture 8.
Chapter 21 Generics 1. Generics - Overview Generic Methods specify a set of related methods Generic classes specify a set of related types Software reuse.
Method Overriding Remember inheritance: when a child class inherits methods, variables, etc from a parent class. Example: public class Dictionary extends.
Sun Certified Java Programmer, ©2004 Gary Lance, Chapter 5, page 1 Sun Certified Java 1.4 Programmer Chapter 5 Notes Gary Lance
Generics and Collections. Introduction Generics New feature of J2SE 5.0 Provide compile-time type safety Catch invalid types at compile time Generic methods.
Chapter 3 Inheritance and Polymorphism Goals: 1.Superclasses and subclasses 2.Inheritance Hierarchy 3.Polymorphism 4.Type Compatibility 5.Abstract Classes.
Inheritance and Access Control CS 162 (Summer 2009)
OOPs Object oriented programming. Abstract data types  Representationof type and operations in a single unit  Available for other units to create variables.
Liang, Introduction to Java Programming, Sixth Edition, (c) 2007 Pearson Education, Inc. All rights reserved Chapter 9 Inheritance and.
Programming With Java ICS201 University Of Ha’il1 Chapter 7 Inheritance.
1 COSC2007 Data Structures II Chapter 9 Class Relationships.
©SoftMoore ConsultingSlide 1 Generics “Generics constitute the most significant change in the Java programming language since the 1.0 release.” – Cay Horstmann.
Chapter 8 Class Inheritance and Interfaces F Superclasses and Subclasses  Keywords: super F Overriding methods  The Object Class  Modifiers: protected,
 In the java programming language, a keyword is one of 50 reserved words which have a predefined meaning in the language; because of this,
Introduction to Object-Oriented Programming Lesson 2.
Method Overriding Remember inheritance: when a child class inherits methods, variables, etc from a parent class. Example: public class Dictionary extends.
Inheritance and Class Hierarchies Chapter 3. Chapter 3: Inheritance and Class Hierarchies2 Chapter Objectives To understand inheritance and how it facilitates.
Access Specifier. Anything declared public can be accessed from anywhere. Anything declared private cannot be seen outside of its class. When a member.
Object orientation and Packaging in Java Object Orientation and Packaging Introduction: After completing this chapter, you will be able to identify.
Terms and Rules II Professor Evan Korth New York University (All rights reserved)
CSCE 314 Programming Languages Java Generics I Dr. Hyunyoung Lee 1.
BY:- TOPS Technologies
Java Programming: Guided Learning with Early Objects Chapter 9 Inheritance and Polymorphism.
Class Inheritance Part II: Overriding and Polymorphism Corresponds with Chapter 10.
Design issues for Object-Oriented Languages
Modern Programming Tools And Techniques-I
Chapter 11 Inheritance and Polymorphism
Inheritance and Polymorphism
03/10/14 Inheritance-2.
COP 3331 Object Oriented Analysis and Design Chapter 5 – Classes and Inheritance Jean Muhammad.
Generics, Lambdas, Reflections
CSC 143 Inheritance.
Overloading and Constructors
Chapter 9 Inheritance and Polymorphism
Chapter 19 Generics Dr. Clincy - Lecture.
OBJECT ORIENTED PROGRAMMING II LECTURE 8 GEORGE KOUTSOGIANNAKIS
Extending Classes.
Java Programming Language
Polymorphism and access control
Week 6 Object-Oriented Programming (2): Polymorphism
Generic programming in Java
Java Inheritance.
CMSC 202 Generics.
Generics, Lambdas, Reflections
Overview of C++ Polymorphism
Chapter 11 Inheritance and Polymorphism Part 2
Final and Abstract Classes
Overloading Each method has a signature: its name together with the number and types of its parameters Methods Signatures String toString()
C++ Object Oriented 1.
Presentation transcript:

CSCE 314: Programming Languages Dr. Dylan Shell Java Generics

Detour: Rules for Method Overriding (1) The argument list should be exactly the same as that of the overridden method. The return type should be the same or a subtype of the return type declared in the original overridden method in the superclass. The access level cannot be more restrictive than that of the overridden method. For example: if the superclass method is declared public then the overriding method in the subclass cannot be either private or protected.

Detour: Rules for Method Overriding (2) Constructors cannot be overridden. A method declared final cannot be overridden. A method declared static cannot be overridden but can be re- declared. If a method cannot be inherited, then it cannot be overridden.

Detour: Rules for Method Overriding (3) A subclass within the same package as the instance's superclass can override any superclass method that is not declared private or final. A subclass in a different package can only override the non-final methods declared public or protected. An overriding method can throw any unchecked exceptions, regardless of whether the overridden method throws exceptions or not. However the overriding method should not throw checked exceptions that are new or broader than the ones declared by the overridden method. The overriding method can throw narrower or fewer exceptions than the overridden method.

Java Generics: History Pizza: 1996-97, extended Java with generics, function pointers, class cases and pattern matching. GJ: 1998 derivative of Pizza; Generics the only extension. Java 1.5: 2004. Modeled after GJ. PolyJ: 1997, would have required changes to JVM. NextGen: 1998, avoids oddities of type erasure, still compatible with JVM and existing binaries. Extension of GJ.

Java Generics: Motivation Typesafe polymorphic containers Without generics: List l = new LinkedList(); l.add(new Integer(0)); Integer x = l.iterator().next(); // need type cast String s = (String) l.iterator().next(); // bad cast exception With generics: List<Integer> l = new LinkedList<Integer>(); Integer x = l.iterator().next(); // no need for type cast String x = l.iterator().next(); // compile−time error what happens without type cast?

Java Generics: Motivation Typesafe polymorphic containers Without generics: List l = new LinkedList(); l.add(new Integer(0)); Integer x = (Integer) l.iterator().next(); // need type cast String s = (String) l.iterator().next(); // bad cast exception With generics: List<Integer> l = new LinkedList<Integer>(); Integer x = l.iterator().next(); // no need for type cast String x = l.iterator().next(); // compile−time error

Java Generics: Motivation Typesafe polymorphic containers Without generics: List l = new LinkedList(); l.add(new Integer(0)); Integer x = (Integer) l.iterator().next(); // need type cast String s = (String) l.iterator().next(); // bad cast exception With generics: List<Integer> l = new LinkedList<Integer>(); Integer x = l.iterator().next(); // no need for type cast String x = l.iterator().next(); // compile−time error

Java Generics: Motivation Typesafe polymorphic containers Without generics: List l = new LinkedList(); l.add(new Integer(0)); Integer x = (Integer) l.iterator().next(); // need type cast String s = (String) l.iterator().next(); // bad cast exception With generics: List<Integer> l = new LinkedList<Integer>(); Integer x = l.iterator().next(); // no need for type cast String x = l.iterator().next(); // compile−time error

Parameterized Classes public class Pair<T, U> { //T, : type variables, also formal type parameters private T a; private U b; public Pair(T t, U u) { a = t; b = u; } public T getFirst() { return a; } public U getSecond() { return b; } } Pair<Integer, String> p = new Pair<Integer, String>(0, ""); // Pair<Integer, String> is an invocation/instance of the generic type // declaration with actual type arguments. Compare to Haskell: data Pair a b = Pair a b getFirst :: Pair a b -> a getFirst (Pair x y) = x getSecond :: Pair a b -> b getSecond (Pair x y) = y

(Mental) Model of Parametrized Classes public class Pair<T, U> { private T a; private U b; public Pair(T t, U u) { a = t; b = u; } public T getFirst() { return a; } public U getSecond() { return b; } } Pair<Integer, String> p = new pair<Integer, String>(0, ""); public class Pair<Object, Object> { private Object a; private Object b; public Pair(Object t, Object u) { a = t; b = u; } public Object getFirst() { return a; } public Object getSecond() { return b; } }

Parametrized Methods Example Explicit instantiation allowed as well: public class ArrayUtil { . . . public static <E> void print(E[] a) { // generic method for (E e : a) System.out.print(e.toString() + " "); System.out.println(); } Rectangle[] rects = . . . ; String[] strs = . . . ; ArrayUtil.print(rects); ArrayUtil.print(strs); Explicit instantiation allowed as well: ArrayUtil.<Rectangle>print(rects); ArrayUtil.<String>print(strs);

Parametric Polymorphism Why does this work? public static <E> void print(E[] a) { for (E e : a) System.out.print(e.toString() + " "); System.out.println(); } In Haskell, this did not work: print :: [a] -> IO () print ls = mapM_ (putStr . show) ls But this did: print :: Show a => [a] -> IO () 13

Parametric Polymorphism (Cont.) Java, too, needs constraints to type parameters Without constraints, only operations that are supported for all types can be applied to values whose types are type parameters. If no constraints, the constraint extends Object is assumed: public static <E extends Object> void print(E[] a) { for (E e : a) System.out.print(e.toString() + " "); System.out.println(); } “E extends Object” justifies toString

Example of Constraints Erroneous: public static <E> void print(List<E> a, E threshold) { for (E e : a) if (e.compareTo(threshold) < 0) // type error !! System.out.print(e.toString() + " "); System.out.println(); }

Example of Constraints OK: public static <E extends Comparable> void print(List<E> a, E threshold) { for (E e : a) if (e.compareTo(threshold) < 0) // type error !! System.out.print(e.toString() + " "); System.out.println(); } Comparable interface itself is really parametrized, as we’ll soon discuss...

Type Parameter with Multiple Bounds Multiple bindings for a single type parameter is allowed: class SortedList<T extends Comparable & Serializable> { . . . } In <T extends T1 & T2 & . . . & Tn>, extends is used in a general sense to mean either “extends” (as in classes) or “implements” (as in interfaces) If one of the bounds is a class, it must be specified first Compare with multiple class constraints in Haskell: smallToString :: (Show a, Ord a) => a -> [a] -> [String] smallToString x xs = map show (filter (< x) xs) *Main> smallToString 5 [1,2,3,4,5,6] ["1","2","3","4"]

Unnamed Type Parameters - Wildcards static void printAll (List<?> l) { for (Object o : l) System.out.println(o); } Wildcards are both a convenience feature (more concise syntax), and to add support for co/contravariance for type parameters (still to be discussed).

Plain Bounded Quantification Example (in C++ like syntax) class Point { public int x; public int y; } class ColorPoint extends Point { public int color; } This establishes: ColorPoint <: Point Foundational paper: Peter Canning, William Cook, Walter Hill, Walter Olthoff, and John C. Mitchell. “F-bounded polymorphism for object-oriented programming” Functional Programming Languages and Computer Architecture, pages 273–280, ACM, 1989.

Subtyping Example class Point { public int x; public int y; } class ColorPoint extends Point { public int color; } Point move(Point a, int dx, int dy) { a.x += dx; a.y += dy; return a; } ... Point p = new Point(); p.x = 0; p.y = 0; p = move(p, 1, 2); ColorPoint cp = new ColorPoint(); cp.x = 0; cp.y = 0; cp.color = 0; cp = move(cp, 1, 2); // Type error! p = move(cp, 1, 2); // OK!

Subtyping Example class Point { public int x; public int y; } class ColorPoint extends Point { public int color; } Point move(Point a, int dx, int dy) { a.x += dx; a.y += dy; return a; } ... Point p = new Point(); p.x = 0; p.y = 0; p = move(p, 1, 2); ColorPoint cp = new ColorPoint(); cp.x = 0; cp.y = 0; cp.color = 0; cp = move(cp, 1, 2); // Type error! p = move(cp, 1, 2); // OK! With just subtyping, the exact type of cp is lost when passed to and returned from move()

Bounded Quantification Subtype polymorphism in itself is not sufficient. A possible fix to this loss of type accuracy is to use parametric polymorphism (instead of subtype polymorphism): <T> T move(T a, int dx, int dy) { a.x += dx; a.y += dy; return a; } Access to members x and y, and operations on them must be justified by some constraints <T extends Point> T move(T a, int dx, int dy) Simple constraint: T itself does not occur in the constraint (in the literature, this is sometimes referred to as bounded quantification [Cardelli, Wegner 85]) Constraint is fixed for all instantiations, which turns out to be too limited

Bounded Quantification Subtype polymorphism in itself is not sufficient. A possible fix to this loss of type accuracy is to use parametric polymorphism (instead of subtype polymorphism): <T> T move(T a, int dx, int dy) { a.x += dx; a.y += dy; return a; } Access to members x and y, and operations on them must be justified by some constraints <T extends Point> T move(T a, int dx, int dy) Simple constraint: T itself does not occur in the constraint (in the literature, this is sometimes referred to as bounded quantification [Cardelli, Wegner 85]) Constraint is fixed for all instantiations, which turns out to be too limited

Problems with Bounded Quantification interface Movable { Movable move(int x, int y); } Define function translate that takes any Movable object, and returns another one of the same type, moved one unit along both axes. translate should have (roughly) the type: ∀T <: Movable.T -> T First attempt (does not work): <T extends Movable> T translate(T m) { return m.move(1, 1); } // type error! move is (essentially) of type (Movable, int, int) -> Movable So, we again hit the problem of subtyping losing information!

Problems with Bounded Quantification interface Movable { Movable move(int x, int y); } Define function translate that takes any Movable object, and returns another one of the same type, moved one unit along both axes. translate should have (roughly) the type: ∀T <: Movable.T -> T First attempt (does not work): <T extends Movable> T translate(T m) { return m.move(1, 1); } // type error! move is (essentially) of type (Movable, int, int) -> Movable So, we again hit the problem of subtyping losing information!

Problems with Bounded Quantification interface Movable { Movable move(int x, int y); } Define function translate that takes any Movable object, and returns another one of the same type, moved one unit along both axes. translate should have (roughly) the type: ∀T <: Movable.T -> T First attempt (does not work): <T extends Movable> T translate(T m) { return m.move(1, 1); } // type error! move is (essentially) of type (Movable, int, int) -> Movable So, we again hit the problem of subtyping losing information!

Binary Method Problem Assume the following interface: interface EqComparable { bool eq(EqComparable o); } Task: Define a function noteq to compute the negation of eq This is what bounded quantification enables: <T extends EqComparable> bool noteq(T t, T u) { return !t.eq(u); } Now define a class MyInt which is EqComparable class MyInt implements EqComparable { bool eq(MyInt o) { ... } // not a valid override bool eq(EqComparable o) { ... } // meaningless comparison }

Binary Method Problem Assume the following interface: interface EqComparable { bool eq(EqComparable o); } Task: Define a function noteq to compute the negation of eq This is what bounded quantification enables: <T extends EqComparable> bool noteq(T t, T u) { return !t.eq(u); } Now define a class MyInt which is EqComparable class MyInt implements EqComparable { bool eq(MyInt o) { ... } // not a valid override bool eq(EqComparable o) { ... } // meaningless comparison }

Binary Method Problem Assume the following interface: interface EqComparable { bool eq(EqComparable o); } Task: Define a function noteq to compute the negation of eq This is what bounded quantification enables: <T extends EqComparable> bool noteq(T t, T u) { return !t.eq(u); } Now define a class MyInt which is EqComparable class MyInt implements EqComparable { bool eq(MyInt o) { ... } // not a valid override bool eq(EqComparable o) { ... } // meaningless comparison }

F-Bounded Quantification F-bounded quantification allows the type parameter being constrained to appear in its own bound: <T extends A<T>> The unsuccessful translate example: <T extends Movable> T translate(T m) { return m.move(1, 1); } may now be written as: interface Movable<T> { T move(int x, int y); } <T extends Movable<T>> T translate<T>(T m) { return m.move(1, 1); }

Binary Method Problem Revisited Assume the following interface: interface EqComparable { bool eq(EqComparable o); } <T extends EqComparable> bool noteq(T t, T u) { return !t.eq(u); } Define class MyInt which is EqComparable class MyInt implements EqComparable { bool eq(MyInt o) { ... } // not a valid override bool eq(EqComparable o) { ... } // meaningless comparison } Now, using F-bounds: interface EqComparable<T> { bool eq(T); } <T extends EqComparable<T>> bool noteq<T>(T t, T u) { return !t.eq(u); } class MyInt implements EqComparable<MyInt> { bool eq(MyInt) { ... } }

Another Example: generic sort <T extends EqComparable<T>> void sort(T[] v) { for(int i = 0; i < v.length; i++) for(int j = 0; j < i; j++) if (v[j].compareTo(v[i]) < 0) swap(v, i, j); }

Summary Minor generalizations of F-bounded polymorphism are the backbone of Java, C#, and Eiffel generics. The essential feature in F-bounds is that bounds are generic too — they change along the argument that is being tested for. Subtyping is one way of expressing constraints, there are others (Haskell type classes, C++ concepts, ML signatures).