1 / 46

Type Inference in Java SE 8

Type Inference in Java SE 8. Danie l Smith Java Language Designer. Overview. Context & terminology Target typing Variable dependencies Lambda expressions & method references Migration experience.

scott
Télécharger la présentation

Type Inference in Java SE 8

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Type Inference in Java SE 8 Daniel SmithJava Language Designer

  2. Overview • Context & terminology • Target typing • Variable dependencies • Lambda expressions & method references • Migration experience

  3. The following is intended to outline our general product direction. It is intended for information purposes only, and may not be incorporated into any contract. It is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. The development, release, and timing of any features or functionality described for Oracle’s products remains at the sole discretion of Oracle.

  4. 1) Context & Terminology

  5. Example interface Chooser { int pick(int arg1, int arg2); <T> T pick(T arg1, T arg2); } chooser.pick(23, “hello”).someMethod();

  6. Overload resolution Which method is i) applicable and ii) best? int pick(int arg1, int arg2); <T> T pick(T arg1, T arg2); chooser.pick(23, “hello”) Applicable means arguments are compatible with parameter types. But we don’t know what “T” means…

  7. Invocation typing What is the generic method’s signature/return for this invocation? <T> T pick(T arg1, T arg2); chooser.pick(23, “hello”).someMethod() In other words, what does “T” mean?

  8. Inference variables • Inference variables are meta-variables for types. They allow us to talk generally about types. (Compare someMethod on previous slide…) • Examples: a, b, s, t, a1, a2 • Examples in types: • t[] • List<t> • Pair<? extends a1, a2[]> • An inference variable (t) is not a type variable (T)

  9. Constraint formulas • Is ArrayList<String> <: List<? extends t> true or false? It depends… • Constraint formulas are assertions that constrain the choices for inference variables: • ArrayList<String> → List<? extends t> • a → int • Map<a1, a2> <: Map<String, ?> • These assertions come from, e.g., arguments passed to generic parameters (replacing the type variables with inference variables).

  10. Bounds Bounds are conclusions drawn from constraint formulas: • a = String • a <: Number • Integer <: a • a <: List<b> • a <: b • false

  11. Reduction To get from a constraint formula to bounds, we reduce it: • HashMap<String, Number[]> →Map<a1, ? extends a2[]> • HashMap<String, Number[]> <: Map<a1, ? extends a2[]> • String = a1, Number[] <: a2[] • String = a1, Number <: a2

  12. Resolution • Given a set of bounds, choose types for the inference variables that satisfy their bounds. • { a = String, b <: Object, Integer <: b }resolves to a=String, b=Integer • { Integer <: a, String <: a }resolves to a = Serializable & Comparable<?> • { a <: Runnable, a <: Closeable }resolves to a = Runnable & Closeable • There is often more than one right answer…

  13. When inference fails Map<String, List<String>> m = …; m.put(name, Collections.emptyList()); error: method put in interface Map<K,V> cannot be applied to given types required: String,List<String> found: String,List<Object> m.put(name, Collections.<String>emptyList());

  14. 2) Target Typing

  15. Poly expressions Poly expressions have different types in different contexts, depending on the target type. List<String> strings = Collections.emptyList(); List<Integer> ints = Collections.emptyList(); Map<String, Integer> m1 = new HashMap<>(); Map<Integer, String> m2 = new HashMap<>();

  16. Contexts for target typing • Assignment (including variable declaration, return statement) List<Float> lf = new ArrayList<>(); • Lambda expression body Supplier<List<Float>> lf = () -> new ArrayList<>() • Conditional expression (? :) List<Float> lf = cond ? null : new ArrayList<>(); • Method argument (including constructors) float average(List<Float> lf) { … } average(new ArrayList<>());

  17. Delayed resolution List<Number> ln = Arrays.asList(1, 2, 3); // Java 7: type error // Java 8: compiles • Overload resolution bounds: { Integer <: t } • Invocation typing bounds: { Integer <: t, t = Number }

  18. Nested invocations List<String> ls=Collections.checkedList(new ArrayList<>(), String.class); • Overload resolution of constructor: { t1 <: Object } • checkedList constraints: ArrayList<_____> → List<t2> Class<String> → Class<t2>

  19. Nested invocations Java 7 Strategy List<String> ls =Collections.checkedList(new ArrayList<>(), String.class); • Overload resolution of constructor: { t1 <: Object } • ‘checkedList’ constraints: ArrayList<Object> -> List<t2> Class<String> -> Class<t2>

  20. Nested invocations Java 8 Strategy List<String> ls =Collections.checkedList(new ArrayList<>(), String.class); • Overload resolution of constructor: { t1 <: Object } • ‘checkedList’ constraints: ArrayList<t1> -> List<t2> Class<String> -> Class<t2>

  21. Overload resolution & target typing Overload resolution is always context-independent.

  22. 3) Variable Dependencies

  23. Declared bounds & dependencies interface Widget extends Comparable<Widget> { … } class Sprog implements Widget { … } <T extends C, C extends Comparable<C>> void sort(List<T> list); { t <: c, c <: Comparable<c> } List<Sprog> sprogs = …; sort(sprogs); { t = Sprog, t <: c, t <: Comparable<c> }

  24. Declared bounds & dependencies Java 7 Strategy <T extends C, C extends Comparable<C>> void sort(List<T> list); List<Sprog> sprogs = …; sort(sprogs); { t = Sprog, t <: c, c <: Comparable<c> } Resolution:t = Sprog, c = CAP#1 extends Comparable<CAP#1> error: invalid inferred types for C; inferred type does not conform to declared bound(s) inferred: Sprog bound(s): CAP#1

  25. Declared bounds & dependencies Java 8 Strategy <T extends C, C extends Comparable<C>> void sort(List<T> list); List<Sprog> sprogs = …; sort(sprogs); { t = Sprog, t <: c, c <: Comparable<c> } { t = Sprog, t <: c, Sprog <: c, c <: Comparable<c> } Sprog <: Comparable<c> c = Widget Resolution:t = Sprog, c = Widget

  26. Incorporation • When adding bounds, identify extra new constraints: • a = S and a = Timplies S = T • a = Sanda <: Timplies S <: T • a = SandT <: aimplies T <: S • S <: aanda <: Timplies S <: T • a = UandS = Timplies S[a:=U] = T[a:=U] • a = UandS <: Timplies S[a:=U] <: T[a:=U]

  27. Nesting & dependencies <C extends Collection<String>> C fill(C coll); String s = fill(new ArrayList<>()).get(0); ArrayList<t> -> c { ArrayList<t> <: c, c <: Collection<String> } ArrayList<t> <: Collection<String> { t = String, ArrayList<String> <: c, c <: Collection<String> }

  28. 4) Lambda Expressions & Method References

  29. Lambda expression typing Implicitly-typed (x, y) ->x.substring(y) Explicitly-typed (String x, int y) ->x.substring(y)

  30. Implicitly-typed lambda as argument <T, K extends Comparator<T>> comparing(Function<T,K> getKey); Comparator<String> byLength = comparing(s -> s.length());

  31. Implicitly-typed lambda as argument <T, K extends Comparator<T>> comparing(Function<T,K> getKey); <T> comparing(ToIntFunction<T> getKey); Comparator<String> byLength = comparing(s -> s.length()); // Error: ambiguous overloads

  32. Explicitly-typed lambda as argument <T, K extends Comparator<T>> comparing(Function<T,K> getKey); <T> comparing(ToIntFunction<T> getKey); Comparator<String> byLength = comparing((String s) -> s.length());

  33. Method reference typing Inexact String::substring Exact String::getLength

  34. Inexact method reference as argument <T, K extends Comparator<T>> comparing(Function<T,K> getKey); <T> comparing(ToIntFunction<T> getKey); Comparator<String> byLower = comparing(String::toLowerCase); // Error: ambiguous overloads

  35. Exact method reference as argument <T, K extends Comparator<T>> comparing(Function<T,K> getKey); <T> comparing(ToIntFunction<T> getKey); Comparator<String> byLength = comparing(String::length);

  36. Overloading for lambdas & method references • Rule of thumb: don’t declare overloads with functional interface types of the same arity <T, K extends Comparator<T>> comparing(Function<T,K> getKey); <T> comparingInt(ToIntFunction<T> getKey); • Exception: some other argument can be used to disambiguate

  37. Interlude: Grab Bag

  38. Grab bag of other new features • Dependency-based ordering of variable resolution • Dependency-based ordering of lambda typing • Exception variables prefer resolving to RuntimeException • Simulate capture of generic return types • More flexibility when unboxing a generic return type

  39. 5) Migration Experience

  40. Get rid of explicit type arguments  Map<String, List<String>> m = …; m.put(name, Collections.<String>emptyList()); becomes m.put(name, Collections.emptyList()); (For methods, grep for “.<”; for diamond, look for common generic types)

  41. Risk of overload resolution changes  void m(Object o) { System.out.println(“x”); } void m(List<Number> ln) { System.out.println(“y”); } m(Arrays.asList(1, 2, 3)); (Note that it is nearly impossible to improve type checking without tripping over this.)

  42. New freedom  • Can use diamond everywhere • Don’t have to be afraid of ? : • Generic methods don’t mind multiple levels of nesting • Can define more sophisticated generic APIs • No more anonymous inner class boilerplate

  43. OpenJDK: Lambda Project JCP: JSR 335 lambda-dev@openjdk.java.net

  44. Graphic Section Divider

More Related