Upload
others
View
2
Download
0
Embed Size (px)
Citation preview
1
Generics in Java and Beyond
Martin Buechi
© 2001 by Martin Büchi
2
Overview
Generics• Abstraction of generic concepts.
• C++ templates (STL), parameterized types, ML polymorphic datatypes and functions, Beta virtual types
• First usage: CLU 1977
Talk overview• Introduction to generic programming• Implementation techniques for generics• Generics in JDK 1.5 (2003)
3
Stack: Generic Pattern & Generics
class Stack {void push(Object o) {…}
Object pop() {…}…
}
// stack of String
Stack s = new Stack();st.push(“Hello”);…
…s = (String)st.pop();
unnecessary cast
st.push(new Object()); // ok
run-time exception
class Stack<A> {void push(A o) {…}
A pop() {…}…
}
// stack of String
Stack<String> s = new Stack<String>();st.push(“Hello”);…
…s = st.pop(); // no cast needed
st.push(new Object()); // compile-time error
public Stack(Class t) {this.t = t;}
private Class t;
if(t.isInstanceOf(o))
exception
4
Bounded Polymorphism
interface Priority {int getPriority();
}class A implements Priority {
public int getPriority() {…}
}class PriorityQueue<E > {
E queue[];
void insert(E e) {…if(e.getPriority() < queue[i].getPriority()) {…}
…}
}
PriorityQueue<A> p = new PriorityQueue<A>();p.insert(new A());
implements Priority
5
F-Bounded Polymorphism
interface Comparable<I> {boolean lessThan(I o);
}class A implements Comparable<A> {
public boolean lessThan(A o) {…}
}class SortedList<E implements Comparable<E>> {
E list[];
void insert(E e) {…if(e.lessThan(list[i])) {…}
…}
}
6
Mix-Ins
interface LessAndEqual<I> {boolean lessThan(I o);
boolean equal(I o);}class A implements LessAndEqual {…}
class Relations<C implements LessAndEqual<C>> extends C {boolean lessThanEqual(Relations<C> a) {
return lessThan(a) || equal(a);
}}
Relations<A> x = new Relations<A>();Relations<A> y = new Relations<A>();if(x.lessThanEqual(y)) {…}
7
Parameterized Methods
public final class Std { public static <T implements Comparable> T min(T a, T b) {
if(a.compareTo(b) <= 0) return a; else return b; }
}
public class Main {
public static void main(String[] args) { Integer b1 = new Integer(2); Integer b2 = new Integer(5); Integer bMin = Std.min(b1, b2);
Date d1 = new Date(101, 05, 10); Date d2 = new Date(101, 03, 8); Date dMin = Std.min(d1, d2); System.out.println("The minimums are: " + bMin + " and " + dMin);
}}
8
Bounds: Name vs Structural Subtyping
class PriorityQueue<E implements Priority> {… e.getPriority() …}
class A implements Priority {int getPriority() {…}
}
class B {int getPriority() {…}
}
//okPriorityQueue<A> p = new PriorityQueue<A>();
// compile-time error with name equivalence, ok with structural equivalencePriorityQueue<B> p = new PriorityQueue<B>();
class PriorityQueue<E where {int getPriority();}> {…}
9
Insufficient Bounds: Duplicates/Overriding
Duplicate methodsclass C<A implements I> {
int m(A s) {return 1;}int m(String s) {return 2;}
}
• Instantiation C<String> illegal: two methods m(String).
Overriding errorclass C<A implements I> extends A {
int m() {return 1;}
}class X implements I {
void m() {…}
}• Instantiation C<X> illegal: int m() cannot override void m().• Negative type information would be a solution
10
Insufficient Bounds: Instance Creation
class C<A implements I> {void f() {
A a = new A();}
}
Actual parameter must be a concrete class• abstract class X implements I {…} C<X> x = new C<X>()
Actual parameter must have an accessible defaultconstructor• class Y implements I {Y(int i) {};} C<Y> y = new C<Y>()
Bound is insufficient• Instantiation that satisfies bound visible from interface may be illegal.
11
Subtyping
Subtyping of parameterized class impliessubtypingclass Collection<A> {…}
class Set<A> extends Collection<A> {…}Collection<X> x = new Set<X>
Instantion with subtype does not imply subtypingclass Collection<A> {…}class Y extends X {…}Collection<Y> y = new Collection<Y>;
Collection<X> x = y; // compile-time errorx.insert(new X()); // would violate soundness
Y[] y = new Y[10];
X[] x = y; // legalx[0] = new X(); //ArrayStoreExc.
12
Implementation: Textual Substitution
Generic declaration treated as textual macro• Source code necessary for instantiation
Big and fast• Every instantiation consumes secondary & primary storage• Speed optimization possible at compile time (limited usefulness)
Full reflective inquiry supportPackage-based accessibility too restrictive• Instantiation of generic class p.x accessing package-protected class p.y
with package-protected class q.z is not possible
Runs on current JVM• Reflection does not reveal genericity (Generic class, instantiation
parameters(s))
C++ templates based on textual substitution
13
Implementation: Heterogeneous Translation
Generic class compiled into extended class file• Compilation of generic class produces generic class file
• Normal class file generated upon instantiation
Rest as textual substitution
14
Implementation: Load-Time Instantiation
Compilation of generic class into class file withextensions for compiler and loader• Class loader creates instantiations
• Change of class loader required, but not of verifier/interpreter (security)
Small in secondary, big at run-time, pretty fast• Only one class file in secondary storage, fast to transmit (applets)
• Run-time memory needed for each instantiation• Run-time (loader, JIT, adaptive) speed optimizations possible
Full reflectionPackage-based accessibility too restrictive• Generic class p.x accessing package-protected class p.y instantiated with
package-protected class q.z is not possible
Minimal changes to JVM required
15
Implementation: Generic JVM
Compilation of generic class into class file withextensions for compiler and JVM• JVM loads, verifies, and executes generic class file
• Change of JVM, including verifier/interpreter (security)
Small in secondary, small at run-time, pretty fast• Only one class file in secondary storage, fast to transmit (applets)
• JVM can optimize run-time memory vs. speed
Full reflectionBig change to JVM required
16
Implementation: Homogeneous Translation
Compilation of generic class into class file withextensions for compiler only• Formal type parameters replaced by bound
• Loss of type safety at run time (e.g., can push Object on stack of Strings)
Small and slow• Only one class file in secondary storage, fast to transmit (applets)
• Only one instance at run time• No speed optimizations possible (small problem for reference types)• Speed penalty due to casts
Limited reflectionRuns on current JVM
17
Generics in Java
Last minute consideration by Gosling and Joy• Scrapped due to time pressure, immature proposal, complexity
Several proposals to add (ECOOP, OOPSLA)Java Community Process• JSR14• Most wanted language feature in Bug Parade
Most likely in JDK 1.5 in 2003Based on GJ• Published in OOPSLA 1998• Basis for javac in JDK 1.3
• GJ contains generic version of Collection API• Binary freely available for download
18
GJ: Overview
F-bounded polymorphismNo mix-ins (parameter as superclass)No change of the virtual machineHomogeneous translationLittle support for reflectionNo instantiation with primitive typesNo non-type parameters (functors, constants, …)Solves the generic legacy problem
19
GJ: Old Code and New Generic Libraries
Compilation: replacement of parameter by bound// GJ source
class PQ<E implements Priority> {E queue[];E removeFirst() {…}
}PQ<A> p = new PQ<A>();p.insert(new A());
A a = p.removeFirst();
Combination with old code• For JVM, generic code is like code adhering to generic pattern
– Code compiled for non-generic version of Collection API works withcompilation of generic API
Compilation of new generic instantiations• Class file extension contains bound and parameter
// Equivalent byte-code for JVM
class PQ {Priority queue[];Priority removeFirst() {…}
}PQ p = new PQ();p.insert(new A())
A a = (A)p.removeFirst();
20
GJ: Retrofitting Old Code
Retrofitting of non-generic binary code// Non-generic class
// only binary available// PriorityQueue.classclass PriorityQueue {
Priority queue[];Priority removeFirst() {…}
}
gjc PriorityQueue.java -retro PathOfClassFile• Adds generic type information from PriorityQueue.java to
PriorityQueue.class.• Does not change byte code used by JVM, only adds information for
correct compilation of instantiations of generic class.
Current GJ comes with retrofitted Collection API
// Typing information for retrofitting
// No/dummy implementation// PriorityQueue.javaclass PriorityQueue<E implements Priority> {
E queue[];E removeFirst() {return null;}
}
21
Try It!
JDK 1.5 now: GJ• http://www.cs.bell-labs.com/~wadler/pizza/gj/
C++ templates (STL)• Unbounded
For the brave: gbeta• Generics in form of virtual types.
• Run-time instantiation of generics• http://www.daimi.aau.dk/~eernst/gbeta/
22
Read More!
Genericity in Java• Java Specification Request 14:
http://java.sun.com/aboutJava/communityprocess/
• Bank, Liskov, and Myers. Parameterized Types and Java. POPL ‘97.• Thorup. Genericity in Java with Virtual Types. ECOOP ‘97.• Agesen, Freund, and Mitchell. Adding Type Parameterization to the
Java Language. OOPSLA 97.
• Bracha, Odersky, Stoutamire, and Wadler. Making the future safe forthe past: Adding Genericity to the Java Programming Language.OOPSLA ‘98.
• Cartwright and Steele. Compatible Genericity with Run-time Typesfor the Java Programming Language. OOPSLA ‘98.
Type theory• Fisher and Mitchell. The Development of Type Systems for Object-
Oriented Languages. Theory and Practice of Object Systems, 1(3):189–220.
23
Summary & Conclusions
Generics are useful• Reuse through instantiation of generic concept
• More compile-time error checking and fewer run-time exceptions• Fewer casts: easier to write and faster to execute
Implementations• Different tradeoffs with respect to secondary and primary memory,
speed, safety, reflection accuracy, and need for changes to the JVM.
Generics in Java• Official support in JDK 1.5, scheduled for 2003• GJ available now, generated code interoperable with normal Java