Post on 15-Dec-2015
<?>
<?>
<?>
<?>
<?>
<?>
<?>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>
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