Title: A FirstClass Approach to Genericity
1A First-Class Approach to Genericity
- Eric Allen
- Rice University
2Outline
- Why generic types are useful
- Natural extensions of the use of genericity
- Analyses and designs of genericity for Java
- GJ and type erasure
- NextGen
- Extension to first-class genericity
- Language design
- Implementation
3Why use generic types?
4Why use generic types?
- AbstractList l new ArrayList()
- l.add(0, new Integer(1))
-
-
- Integer i l.get(0)
5Solution 1 Insert Casts
- AbstractList l new ArrayList()
- l.add(0, new Integer(1))
-
-
- Integer i (Integer)l.get(0)
6Solution 2 Duplicate Code
7Solution 3 Extend the Type System
8Generic Java
- public class AbstractListltT extends Objectgt
- public T get(int pos)
-
-
- public class ArrayListltTgt extends AbstractListltTgt
- public void add(int pos, T elt)
- public T get(int pos)
-
9Run-time Generic Type Operations
- Generic types also suggest ways to increase
expressiveness, e.g., NextGen - (Cartwright and Steele, 96)
- new T()
- (T)expression
- expression instanceof T
10First-Class Genericity
class TimeStampedltTgt extends T public long
time TimeStamped() super() time
new java.util.Date().getTime()
11Mixins
- Classes parameterized by their parents
- Originated in the Lisp community
- Used informally in C (via STL)
- Jam extension to Java 1.1
12Advantages of First-Class Genericity
- Integrates a mixin facility with generic types
- Provides the foundation for a first-class module
system
13Structural vs. Nominal Type Systems
abstract class Multiset abstract public void
insert(Object o) abstract public void
remove(Object o) abstract public boolean
isMember(Object o) abstract class Set
abstract public void insert(Object o)
abstract public void remove(Object o) abstract
public boolean isMember(Object o)
14Generic Types in the Nominal World
- Pizza, GJ, JSR-14
- Formal modeling Featherweight GJ
- Type Erasure
15Type Erasure
- Generic types are used only for type checking
- After type checking, all types are erased to
their non-parametric upper bounds
16Type Erasure
- TreeltTgt ? Tree
- TreeltIntegergt ? Tree
- T (in class Tree) ? Object
17Type Erasure Advantages
- Erased generic classes look like their
non-generic counterparts - No code bloat
18Type Erasure Disadvantages
- Second-class genericity
- type parameters not bound in static contexts
- no casting to type parameters
- no new operations on type parameters
- no instanceof operations on type parameters
- no naked type parameters in extends clauses
19NextGen (Cartwright and Steele 96)
- Encode parametric types in the existing class
hierarchy - Generate a new class for each instantiation
- Factor out common code
20NextGen
- Quasi-first-class genericity
- Compatible with first-class genericity
- type parameters bound in static contexts
- casting
- new expressions
- instanceof tests
- extends clauses of class definitions
21Naïve implementation of generic types over the
Java class structure
22Illegal Class hierarchy in naive JVM Class
Representation.
23Simple Parametric Type Hierarchy and its JVM
Class Representation
24Snippet Methods
- Expressions involving run-time type operations
are turned into calls on snippet methods - Abstract in the base class
- Overridden in each instantiation class
- (T)e ? snipn(e)
25Implementation
- Generate class files for each instantiation of a
parametric type - Mangle parametric type references so that they
are valid JVM identifiers - Names of instantiation classes are encoded to
prevent clash with inner classes
26Name Mangling
- Left angle bracket to L
- Right angle bracket to R
- Comma to C
- Period (dot) to D
27Implementation (naïve strategy)
- StackltIntegergt
- becomes
- StackLIntegerR
28Complications with Instantiation
- class CltTgt
- public Object nest(int n)
- if (n 0)
- return this
-
- else
- return new CltCltTgtgt().nest(n-1)
-
-
29Template Class Files
- All instantiations of a given class will have
essentially the same form - We generate a template class file with this form
at compile time - At run-time, we use a special class loader that
uses the template to construct instantiations on
demand
30Elegance of the Classloader Design
- Avoids limitations on instantiation (as in, e.g.,
C) - Follows precedent of many existing tools (Ant,
JUnit, etc.) - A defensible design strategy even if we disregard
legacy considerations - Efficient!
31Can we extend NextGen to support first-class
genericity?
- type parameters bound in static context
- casting
- new expressions
- instanceof tests
- extends clauses of class definitions
32Can we extend NextGen to support first-class
genericity?
class TimeStampedltTgt extends T public long
time TimeStamped() super() time
new java.util.Date().getTime()
33The Safe Instantiation Principle
- Instantiating a generic type in a way that meets
the declared constraints should not cause an
error. - Important for effective error diagnosis
- Violated by C
- Violated by GJ
34Formal Analysis
- Construct a small, formal language
- Core calculus of first-class generic types
- Extension of Featherweight GJ
- Proof of type soundness of the new calculus
35Type-Checking new Expressions
- How can we know the signatures of the
constructors for an instantiation of a type
variable?? - new T(0, hello, true)
- (important for NextGen too)
36Solution 1 Augment interfaces
- interface I
- init()
- init(int)
-
-
- Then every subclass must include the constructor
signatures of its parent!
37Solution 2 with clauses
- Allow type bounds to include information on what
constructors are available in instantiations - class TimeStamped lt
- T extends Object with init(), init(int)
- gt
38with clauses
- Declared constructors can be called within body
of generic class - All instantiations must obey the with clauses
- Can be type-checked locally (even for
instantiations with type variables)
39Abstract Methods in Parent Instantiations
- The instantiation of a parent class may contain
additional abstract methods - Since a mixin class might not be abstract, this
possibility breaks type soundness
40Solution Augmented with clauses
- class TimeStamped lt
- T with
- init()
- init(int)
- abstract compareTo(Object)
-
- gt extends T
-
-
41Cyclic and Infinite Class Hierarchies
class CltX with ...gt extends X ... class D
extends CltDgt ... D lt CltDgt lt D lt CltDgt lt
42Cyclic and Infinite Class Hierarchies
class C1ltX with ...gt extends X ... class C2ltX
with ...gt extends X ... class D1 extends
C1ltD0gt ... class D0 extends C2ltD1gt ... D0 lt
C2ltD1gt lt D1 lt C1ltD0gt lt D0
43Infinite Class Hierarchies
class CltX with ...gt extends DltCltCltXgtgtgt
... class DltX with ...gt extends X
... DltCltObjectgtgt lt CltObjectgt lt
DltCltCltObjectgtgtgt lt CltCltObjectgtgt lt
DltCltCltCltObjectgtgtgtgt lt ...
44Potential Solutions
- Prohibit extension of mixin classes
- Erase all mixins/secondary mixins, and check for
cycles in the erased class headers
45Accidental Method Overriding
- A mixin may attempt to introduce a new method and
inadvertently override a method in a parent
instantiation! - Breaks type soundness
- Programmers cant interoperate with each others
classes
46Accidental Overriding Breaks Type Soundness
class C Integer m() return new
Integer(0) class DltT with gt extends
T String m() return string
47Accidental Overriding Breaks Type Soundness
- Integer typeBreaker(C c)
- return c.m()
-
- typeBreaker(new DltCgt())
48Accidental Overriding is Beyond Local Static
Checking
- class EltT with gt
-
- new DltTgt()
-
-
- new EltCgt()
49Solution Hygienic Mixins
- Ambiguous method calls are resolved based on the
static type of the receiver - Methods are overridden only if they are declared
in the bound of a parent type
50Hygienic Mixins
- Integer typeBreaker(C c)
- return c ? C.m()
-
- typeBreaker(new DltCgt())
- ? new DltCgt() ? C.m()
51The bound on T does not include m()
class C Integer m() return new
Integer(0) class DltT with gt extends
T String m() return string
52Hygienic Mixins
- Integer typeBreaker(C c)
- return c ? C.m()
-
- typeBreaker(new DltCgt())
- new DltCgt() ? C.m()
- new DltCgt() C.m()
53Hygienic Mixins
- Integer typeBreaker(C c)
- return c ? C.m()
-
- typeBreaker(new DltCgt())
- new DltCgt() ? C.m()
- new DltCgt() C.m()
- new Integer(0)
54Implementing Hygienic Mixins on the JVM
- Every method introduced in a class is prefixed
with the greatest superclass in which it is known
to be introduced - A forwarding method is added for each method
declared in each implemented interface
instantiation
55Implementing Hygienic Mixins on the JVM
- Forwarding methods for implemented interfaces are
prefixed with the name of the interface
instantiation - Free type parameters are filled in by the class
loader
56Implementing Hygienic Mixins on the JVM
interface IltTgt T m() class CltS with gt
extends S implements IltSgt S m()
... class D implements IltStringgt String
m() ... new CltDgt()
57Implementing Hygienic Mixins on the JVM
interface IltTgt T IL0Rm() class CltS
with gt extends S implements IltSgt S Cm()
... S IL0Rm() return Cm()
class D implements IltStringgt String
Dm() ... String ILStringRm() return
Dm()
58Implementing Hygienic Mixins on the JVM
- String typeBreaker(IltStringgt i)
- return i.m()
-
- typeBreaker(new CltDgt())
59Implementing Hygienic Mixins on the JVM
- String typeBreaker(ILStringR i)
- return i.ILStringRm()
-
- Q. What if the static type of the receiver
- wasnt ground?
- A. The method call would be snippetized!
60Implementation
- Retrofitted GJ compiler with a 15,000 line unit
test suite - Refactored GJ compiler that faciliates extension
- Extended GJ to NextGen with modified class loader
- Extended NextGen to support
- non-hygienic first-class genericity
61Conclusion and Future Research
- Application of first-class genericity to a build
a module system - Integration of first-class genericity with raw
types, e.g., C for class CltTgt (Igarashi and
Viroli) - Benchmarking of hygienic mixins
62Appendices
63Type Erasure Complications
- class SetltTgt
- public SetltTgt adjoin(T newElement)
-
-
-
-
64Type Erasure Complications
- class MySet extends SetltIntegergt
- public SetltIntegergt adjoin(Integer newElement)
-
-
-
-
65Type Erasure Complications
- class MySet extends Set
- public Set adjoin(Integer newElement)
-
-
-
-
66Bridge Methods
- public Set adjoin(Object newElement)
- return adjoin((Integer)newElement)
-