wildcards in the java™ programming language neal gafter with thanks to mads torgersen, university...

55
<?> <?> <?> <?> <?> <?> <?> Wildcards in the Java™ Programming Language Neal Gafter with thanks to Mads Torgersen, University of Aarhus

Upload: jakob-marvin

Post on 15-Dec-2015

220 views

Category:

Documents


0 download

TRANSCRIPT

<?>

<?>

<?>

<?>

<?>

<?>

<?>Wildcards

in the Java™ Programming Language

Neal Gafter

with thanks to

Mads Torgersen, University of Aarhus

<?>

<?>

<?>

<?>

<?>

<?>

<?>Wildcards

● Genericity – Improves type system expressiveness

– Based on parametric abstraction

● The abstraction gap:– Clashes with object-oriented (subtype)

abstraction

● Wildcards– Mediate the two modes of abstraction

– Address deep type-theoretic issues

<?>

<?>

<?>

<?>

<?>

<?>

<?>The Wildcards Project

● University of Aarhus– Mads Torgersen, Erik Ernst, Peter von der Ahé

and Christian Plesner Hansen● Sun Microsystems

– Gilad Bracha and Neal Gafter● Based on previous research by

– Mads Torgersen & Kresten Krab Thorup– Mirko Viroli & Atsushi Igarashi

<?>

<?>

<?>

<?>

<?>

<?>

<?>Project Results

● Design of the wildcard mechanism– Mediation of the abstraction gap

– Integration with other language features

● Implementation– javac, the Java compiler

– Java Platform APIs

● Part of JDK1.5 (Tiger)

<?>

<?>

<?>

<?>

<?>

<?>

<?>Java Genericity

interface List extends Collection { void add(Object element); Object get(int index); ...}

<?>

<?>

<?>

<?>

<?>

<?>

<?>Java Genericity

interface List extends Collection { void add(Object element); Object get(int index); ...}

List numbers = new ArrayList();numbers.add(new Integer(7));Number n = (Number)numbers.get(0);

<?>

<?>

<?>

<?>

<?>

<?>

<?>Java Genericity

List numbers = new ArrayList();numbers.add(new Integer(7));Number n = (Number)numbers.get(0);

interface List<T> extends Collection<T> { void add(T element); T get(int index); ...}

<?>

<?>

<?>

<?>

<?>

<?>

<?>Java Genericity

interface List<T> extends Collection<T> { void add(T element); T get(int index); ...}

List<Number> numbers = new ArrayList<Number>();numbers.add(new Integer(7));Number n = numbers.get(0);

<?>

<?>

<?>

<?>

<?>

<?>

<?>Static typecheck

List<Number> numbers = ...numbers.add(”Seven”);Number n = numbers.get(0);

List numbers = ...numbers.add(”Seven”);Number n = (Number)numbers.get(0);

<?>

<?>

<?>

<?>

<?>

<?>

<?>Static typecheck

List<Number> numbers = ...numbers.add(”Seven”);Number n = numbers.get(0);

List numbers = ...numbers.add(”Seven”);Number n = (Number)numbers.get(0);

Runtime type error!

<?>

<?>

<?>

<?>

<?>

<?>

<?>Static typecheck

List<Number> numbers = ...numbers.add(”Seven”);Number n = numbers.get(0);

List numbers = ...numbers.add(”Seven”);Number n = (Number)numbers.get(0);

Compile time error

<?>

<?>

<?>

<?>

<?>

<?>

<?>Object-Oriented Abstraction

Common view on common properties

Collection

ListSet

<?>

<?>

<?>

<?>

<?>

<?>

<?>Object-Oriented Abstraction

Common view on common properties

Collection

ListSet

List l = ...;Collection c = l;

<?>

<?>

<?>

<?>

<?>

<?>

<?>Object-Oriented Abstraction

Pointwise subtyping

Collection<Number>

List<Number>Set<Number>

List<Number> nl = ...;Collection<Number> nc = nl;

<?>

<?>

<?>

<?>

<?>

<?>

<?>Parametric Abstraction

What is the common view?

List<Number>List<String>

?

<?>

<?>

<?>

<?>

<?>

<?>

<?>In the ”old” days...

...any List was just a List

List

ListList

List numbers = ...;List things = numbers;things.add(”Seven”);Number n = (Number)number.get(0);

<?>

<?>

<?>

<?>

<?>

<?>

<?>In the ”old” days...

...any List was just a List

List

ListList

List numbers = ...;List things = numbers;things.add(”Seven”);Number n = (Number)number.get(0);

Runtime type error!

<?>

<?>

<?>

<?>

<?>

<?>

<?>

Number[] numbers = ...;Object[] things = numbers; things[0] = ”Seven”;Number n = numbers[0];

The Array approach

Runtime store check on every assignmentObject[]

Number[]String[]

<?>

<?>

<?>

<?>

<?>

<?>

<?>

Number[] numbers = ...;Object[] things = numbers; Things[0] = ”Seven”;Number n = numbers[0];

The Array approach

Runtime store check on every assignmentObject[]

Number[]String[]

Runtime type error!

<?>

<?>

<?>

<?>

<?>

<?>

<?>Can we do the same for List?

List<Object>

List<Number>List<String>

List<Number> numbers = ...;List<Object> things = numbers; things.add(”Seven”);Number n = numbers.get(0);

Runtime type error?

?

<?>

<?>

<?>

<?>

<?>

<?>

<?>Can we do the same for List?

Erasure: No type argument info at runtime

List<Object>

List<Number>List<String>

List<Number> numbers = ...;List<Object> things = numbers; things.add(”Seven”);Number n = numbers.get(0);

Runtime type error?

?

<?>

<?>

<?>

<?>

<?>

<?>

<?>Can we do the same for List?

Erasure: No type argument info at runtime

List<Object>

List<Number>List<String>

List<Number> numbers = ...;List<Object> things = numbers; things.add(”Seven”);Number n = numbers.get(0);

Runtime type error!

<?>

<?>

<?>

<?>

<?>

<?>

<?>Can we do the same for List?

No type argument info at runtime

List<Object>

List<Number>List<String>

List<Number> numbers = ...;List<Object> things = numbers; things.add(”Seven”);Number n = numbers.get(0);

Compile time error!

<?>

<?>

<?>

<?>

<?>

<?>

<?>The raw types approach

List

List<Number>List<String>

List<Number> numbers = ...; List things = numbers; things.add(”Seven”);Number n = numbers.get(0);

?

<?>

<?>

<?>

<?>

<?>

<?>

<?>The raw types approach

Compile time type check undermined

List

List<Number>List<String>

List<Number> numbers = ...; List things = numbers; things.add(”Seven”);Number n = numbers.get(0);

Runtime type error!

?

<?>

<?>

<?>

<?>

<?>

<?>

<?>The raw types approach

Compile time type check undermined

List

List<Number>List<String>

List<Number> numbers = ...; List things = numbers; things.add(”Seven”);Number n = numbers.get(0);

Compile time warning

<?>

<?>

<?>

<?>

<?>

<?>

<?>The raw types approach

Compile time type check undermined

List

List<Number>List<String>

List<Number> numbers = ...; List things = numbers; things.add(”Seven”);Number n = numbers.get(0);

Compile time warning

<?>

<?>

<?>

<?>

<?>

<?>

<?>The GJ approach

Object

List<Number>List<String>

List<Number> numbers = ...;Object things = numbers; things.add(”Seven”);Object o = things.get(0);

<?>

<?>

<?>

<?>

<?>

<?>

<?>The GJ approach

Object

List<Number>List<String>

List<Number> numbers = ...;Object things = numbers; things.add(”Seven”);Object o = things.get(0);

Compile time error!

<?>

<?>

<?>

<?>

<?>

<?>

<?>The GJ approach

Cannot use common interface

Object

List<Number>List<String>

List<Number> numbers = ...;Object things = numbers; things.add(”Seven”);Object o = things.get(0);

Compile time error!

<?>

<?>

<?>

<?>

<?>

<?>

<?>The GJ approach

Cannot use common interface

Object

List<Number>List<String>

List<Number> numbers = ...;Object things = numbers; things.add(”Seven”);Object o = things.get(0);

Compile time error!

<?>

<?>

<?>

<?>

<?>

<?>

<?>

Requirements for a common view

● It should be some kind of List– so that we can safely get elements out of it

● It should prevent insertion of wrong elements– to avoid heap pollution

● It should do so at compile time– because we have no runtime type argument info

● It must prevent insertion of any elements– because it is a share view of all Lists

<?>

<?>

<?>

<?>

<?>

<?>

<?>Wildcards

”List of something ”

List< >

List<Number>List<String>

?

<?>

<?>

<?>

<?>

<?>

<?>

<?>Wildcards

”List of something ”

List< >

List<Number>List<String>

?

<?>

<?>

<?>

<?>

<?>

<?>

<?>Wildcards

”List of something ”

List<?>

List<Number>List<String>

List<Number> numbers = ...;List<?> things = numbers; things.add(”Seven”);Object o = things.get(0);

<?>

<?>

<?>

<?>

<?>

<?>

<?>Wildcards

”List of something ”

List<?>

List<Number>List<String>

List<Number> numbers = ...;List<?> things = numbers; things.add(”Seven”);Object o = things.get(0);

<?>

<?>

<?>

<?>

<?>

<?>

<?>Wildcards in Collections

package java.util;

public interface Collection<E> { boolean containsAll(Collection<?> c); boolean removeAll(Collection<?> c); ...}

<?>

<?>

<?>

<?>

<?>

<?>

<?>Can we do better?

Integer and Float are related

List<?>

List<Integer>List<Float>

<?>

<?>

<?>

<?>

<?>

<?>

<?>Bounded Wildcards

Numbers come out

List<? extends Number>

List<Integer>List<Float>

List<Integer> ints = ...;List<? extends Number> numbers = ints;Number n = numbers.get(0);numbers.add(.7F);

<?>

<?>

<?>

<?>

<?>

<?>

<?>Bounded Wildcards

Adding still prohibited

List<? extends Number>

List<Integer>List<Float>

List<Integer> ints = ...;List<? extends Number> numbers = ints;Number n = numbers.get(0);numbers.add(.7F);

<?>

<?>

<?>

<?>

<?>

<?>

<?>Extends-bounds in Collections

package java.util;

public interface Collection<E> {

boolean containsAll(Collection<?> c);

boolean removeAll(Collection<?> c);

boolean addAll(Collection<? extends E> c);

...

}

<?>

<?>

<?>

<?>

<?>

<?>

<?>

What can we do about adding?

Adding still prohibited

List<? extends Number>

List<Integer>List<Number>

<?>

<?>

<?>

<?>

<?>

<?>

<?>Super-bounded Wildcards

List<? super Integer>

List<Integer>List<Number>

List<Number> numbers = ...;List<? super Integer> ints = numbers;ints.add(7);Integer i = ints.get(0);

<?>

<?>

<?>

<?>

<?>

<?>

<?>Super-bounded Wildcards

Only Objects come out

List<? super Integer>

List<Integer>List<Number>

List<Number> numbers = ...;List<? super Integer> ints = numbers;ints.add(7);Integer i = ints.get(0);

<?>

<?>

<?>

<?>

<?>

<?>

<?>TreeSet Constructors

package java.util;

public class TreeSet<E>

implements OrderedSet<E> {

public TreeSet(OrderedSet<E> c);

public TreeSet(Collection<? extends E> c);

public TreeSet(Comparator<? super E> c);

...

}

<?>

<?>

<?>

<?>

<?>

<?>

<?>Collections utility methods

package java.util;

public class Collections { public static void reverse(List<?> list); public static void shuffle(List<?> list); public static <T> void fill( List<? super T> list, T obj); public static <T> void copy( List<? super T> dest, List<? extends T> src); ...}

T

<?>

<?>

<?>

<?>

<?>

<?>

<?>Subtyping with wildcards

List<? extends Number>

List<? extends Integer> List<Number>

List<Integer>

List<?>

<?>

<?>

<?>

<?>

<?>

<?>

<?>Subtyping with wildcards

List<? super Integer>

List<? super Number> List<Integer>

List<Number>

List<?>

<?>

<?>

<?>

<?>

<?>

<?>

<?>Type inference

Better types to choose from

<T> T choose(T fst, T snd) { ...}

List<Number> numbers = ...Set<String> strings = ...

Collection<?> c = choose(numbers,strings)

<?>

<?>

<?>

<?>

<?>

<?>

<?>Type inference

Built-in condition expression

Boolean b = ...List<Number> numbers = ...Set<String> strings = ...

Collection<?> c = b ? numbers : strings

<?>

<?>

<?>

<?>

<?>

<?>

<?>Capture

package java.util;

public class Collections { public static void reverse(List<?> list); public static void shuffle(List<?> list); public static <T> void fill( List<? super T> list, T obj); public static <T> void copy( List<? super T> dest, List<? extends T> src); ...}

<?>

<?>

<?>

<?>

<?>

<?>

<?>Capture

package java.util;

public class Collections { public static void reverse(List<?> list); public static void shuffle(List<?> list); public static <T> void fill( List<? super T> list, T obj); public static <T> void copy( List<? super T> dest, List<? extends T> src); ...}

How is reverse() implemented?

<?>

<?>

<?>

<?>

<?>

<?>

<?>Capture

public static void reverse(List<?> list) { rev(list); } private static <T> void rev(List<T> list) { for (int i = 0; i < list.length/2; i++) { int j = list.length - i - 1; T tmp = list.get(i); list.set(i, list.get(j)); list.set(j, tmp); } }}

<?>

<?>

<?>

<?>

<?>

<?>

<?>Capture

public static void reverse(List<?> list) { rev(list); } private static <T> void rev(List<T> list) { for (int i = 0; i < list.length/2; i++) { int j = list.length - i - 1; T tmp = list.get(i); list.set(i, list.get(j)); list.set(j, tmp); } }}

Capture

<?>

<?>

<?>

<?>

<?>

<?>

<?>Wildcard conclusions

● Bridges the gap between object-oriented and polymorphic abstraction

● Simpler and more precise signatures● Better type inference● All over the JDK 5 APIs

http://java.sun.com/j2se/1.5.0