Java gets a closure


Published on

Presentation from Krakow Java Developers Day 2011 about future of Java - closures, defender methods etc.

Published in: Technology, Education
1 Like
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide
  • It would be ambiguous with a cast (is this a lambda with on argument or cast of a nilary lambda to x?):(x)->{ 3.14; }
  • Closure is a function together with referencing environment for the free variables of that function.
  • Promotes side effect free programming modelNo wunderbars
  • interface Converter { int convert(String s); }classInteger { publicstaticString toString(inti) { ... }}Converter lambda = i -> Integer.toString(i);Converter methodRef = Integer::toString;
  • Java gets a closure

    1. 1. Java gets a closureTomasz Kowalczewski
    2. 2. Agenda• Lambdas and closures• Java syntax• Functional interfaces• Implementation notes• Defender methods and interface evolution• Library changes• Lambda related language changes
    3. 3. Lambda expression• First class function that closes over free variables in its lexical context.• Lambda exprssion is another name for an anonymous function e.g. function not bound to an identifier.• In Java it includes an optional list of type parameters, a list of formal parameters, and an expression or block expressed in terms of those parameters.
    4. 4. Examples• Haskell: free variablesx -> x + xx -> x * y• Scala:val isBelow = ( y : Int ) => y < threshold• C#:Predicate<string> p = it => it.Length < maxLength;• C++:[&count](int n){ return n * (++count); }
    5. 5. Why we hate anonymous inner classes?• Java already has a form of closures - anonymous inner classesList<Person> list = new ArrayList<>();Collections.sort(list, new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { return p1.getName().compareTo(p2.getName()); }});
    6. 6. Why we hate anonymous inner classes?• Bulky syntax• Inability to capture non-final local variables• Transparency issues surrounding the meaning of return, break, continue, and this• No nonlocal control flow operators
    7. 7. Will we love lambda expressions?• Bulky syntax• Inability to capture non-final local variables• Transparency issues surrounding the meaning of return, break, continue, and this• No nonlocal control flow operators
    8. 8. Lambda syntaxList<Person> list = new ArrayList<>();Collections.sort(list, (p1, p2) -> p1.getName().compareTo(p2.getName()));List<Person> list = new ArrayList<>();Collections.sort(list, new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { return p1.getName().compareTo(p2.getName()); }});
    9. 9. Lambda syntaxLambdaExpression: TypeParametersopt LambdaParameters -> LambdaBody(int i) -> { System.out.println(i+1); }(String s, int offset) -> { return s.charAt(offset) }<T> (T i) -> { }
    10. 10. Lambda syntaxLambdaExpression: TypeParametersopt LambdaParameters -> LambdaBodyLambdaParameters: Identifier ( InferredFormalParameterList ) ( FormalParameterListopt )‘i -> { System.out.println(i+1); }(s, offset) -> { return s.charAt(offset) }() -> {}
    11. 11. Lambda syntaxLambdaExpression: TypeParametersopt LambdaParameters -> LambdaBodyLambdaBody: Expression Block(r) -> r *r *3.14() -> System.out.println(i +1)(s, offset) -> s.charAt(offset)(s, offset) -> { return s.charAt(offset); }
    12. 12. Invalid syntax examples• Either types/modifiers are infered or we need to specify all of them:(final x) -> {}(int x, y) -> 3.14• Lambda body is either an expression (no brackets) or a block (brakcets and return statement needed):() -> { 3.14; }• Only unary lambda may omit parentheses:i, j -> i*j• There is no nilary syntax: -> "foo"
    13. 13. What is the type of a lambda?• There will be no function types in Java 8• We need to define how lambdas interact with other parts of Java• We need ways to store, pass and execute them• We need to define how closure conversion is performed ▫ Greatly influences lambda flexibility e.g. referencing local mutalbe variables
    14. 14. Functional interfaces• Previously known as SAM interfaces ▫ SAM = Single Abstract Method• Interfaces that define one method ▫ Public methods defined by Object do not countinterface Runnable { void run(); }interface Callable<T> { T call(); }interface Comparator<T> { int compare(T o1, T o2); boolean equals(Object obj);}
    15. 15. Closure conversion• Lambda expresion is converted to an instance of a functional interface• It can appear in assignment, invocation and casting contexts• The type lambda is converted to is infered from the context ▫ Target typing• Parameter types of the lambda are also inferred
    16. 16. Type inferenceinterface Processor<T> { void process(Context c, T item);}Processor<Integer> p = (Context c, Integer i) -> { ... };Processor<Integer> p = (c, i) -> { ... };
    17. 17. Local variable capture• Lambda expressions can refer to effectively final local variables from the enclosing scopeint getAdultCount(List<Person> people, int threshold) { return Collections.filter(people, p -> p.getAge() > threshold).size();}void registerNotifier(JButton button, JLabel label) { button.addActionListener(e -> label.setText(""));}
    18. 18. Local variable capture• Cannot do this:int accumulatedExperience = 0;people.forEach(p -> accumulatedExperience += p.getEmploymentYears());• Don’t even try this:/* final */ int[] accumulatedExperience = { 0 };people.forEach(p -> accumulatedExperience[0] += p.getEmploymentYears());• Try this:/* final */ AtomicInteger accumulatedExperience = new AtomicInteger();people.forEach(p -> accumulatedExperience.addAndGet(p.getEmploymentYears()));• Best solution:people.reduce(0, (value, p) -> value +p.getEmploymentYears());people.reduce(0, Math::add);
    19. 19. Lexical scoping• All identifiers retain their meaning inside lambda expression• The meaning of this does not change.• Lambda formals cannot shadow variables from enclosing scope.• There is no non-local control flow
    20. 20. Lexical scopinginterface ConfigFilter { String KEY = "configuration.source"; boolean matches(Properties properties);}class FileConfigurator { String VALUE = "file://"; public void configure(List<Properties> list) { configure(list, p -> p.getProperty(ConfigFilter.KEY).startsWith(VALUE)); } void configure(List<Properties> l, ConfigurationFilter f) { ... }}
    21. 21. Lambda self reference• Definite assignment rules say when a variable is definitely assigned ▫ e.g. if it is a local variable it can be safely used• Definite uassignment say when a variable is definitely unassigned ▫ e.g. so that it can be assigned if it is final• Function fib = n -> { n == 0 ? 1 : n *fib.apply(n -1) };
    22. 22. Method references• Method reference is a shorthand for a lambda invoking just that method• Static methods simply translate like lambda with same arguments and return type:class Math { public static int max(int a, int b) { ... }}interface Operator<T> { T eval(T left, T right);}Operator<Integer> lambda = (a, b) -> Math.max(a, b);Operator<Integer> methodRef = Math::max;
    23. 23. Method referencesclass Reducer { <T> static reduce(T base, Operator<T> op, T... items) { for(T item : items) { base = op.eval(base, item); } }}// result is 9Reducer.reduce(0, Math::max, 1, 6, 9, 8);// result is 24Reducer.reduce(0, Math::add, 1, 6, 8, 9);
    24. 24. Method references• Non static method reference of type T translates like lambda with an additional argument of type T:interface Mapper<T, U> { U map(T t);}Mapper<String, Integer> lambda = s -> s.length;Mapper<String, Integer> methodRef = String::length;int getMaxTenure(List<Pereson> people) { return Collections.mapreduce(people, Person::getEmploymentTime, 0, Math::max);}
    25. 25. Method references• Instance method reference translates like lambda with same arguments and return type (and implicit receiver)Callable<Integer> lambda = () -> "test".length();Callable<Integer> c = "test"::length;
    26. 26. Method referencesExecutorService exec = Executors.newFixedThreadPool(4);ServerSocket socket = new ServerSocket();socket.bind(new InetSocketAddress(61000));Callable<Socket> callable = socket::accept;Future<Socket> socket = exec.submit(callable);URL url = new URL("");URLConnection connection = url.openConnection();Future<InputStream> s = exec.submit(url::openStream);
    27. 27. Constructor references• Basically same as method referencesCallable<Person> p = Person::new;• Generic type constructorLinkedList<Integer>::new• Raw type constructorLinkedList::new• Generic constructor with type argumentFoo::<Integer>new
    28. 28. Constructor referencesMapMaker maker = new MapMaker();ConcurrentMap<String, Integer> map;map = maker.<String, Integer>makeComputingMap(Integer#new);
    29. 29. Exception transparency• Generic exceptions are cumbersome to use• Libraries either use interface with methods that throw Exception or throw nothinginterface Runnable {}interface Callable<V> { V call() throws Exception}interface Callable<V, E extends Exception> { V call() throws E}
    30. 30. Exception transparencyinterface Callable<V, throws E> { V call() throws E}class Executor { static <V, throws E> execute(Callable<V, E>) throws E;}Callable<Integer, IOException> c = ...Executor.execute(c); // Throws IOExceptionCallable<Integer> d = ...Executor.execute(d); // Throws nothingCallable<Integer, ExecutionException, BadBreathException> e = ...Executor.execute(e); // Throws ExecutionException, BadBreathException
    31. 31. Translation to inner classespublic class SimpleLambda { Runnable r = new Runnable() { public void run() { } };}public class SimpleLambda { Runnable r = () -> {};}• Compiling this source files will each time generate two classes: ▫ SimpleLambda.cass ▫ SimpleLambda$1.class• In both situations classes are almost identical
    32. 32. Translation to method handles• Try compiling with option -XDlambdaToMethod• This will generate one class file.• It will contain additional elements: ▫ Static method called lambda$0 with compiled lambda body ▫ Bootstrap method that will call ProxyHelper to generate interface proxy ▫ Calls to will be dispatched through MethodHandle ▫ InvokeDynamic instruction at instantiation callsite
    33. 33. Extension Methods
    34. 34. Extension methods• Programming style would be different if Java had closures from day one• Different library designs, different collection classes• Adding closures without library support would be dissapointing• When interface is published it is effectively freezed – adding new methods will break existing implementations
    35. 35. Extension methods• We would like to be able to write:list.sortBy(Person::getFirstName).filter(Person:: isEmployed).filter(p -> p.getAge() <30).forEach(System.out::println); -> s.getScore()).reduce(0.0, Math::max);
    36. 36. Static extension methods• In C# they enable adding methods to existing types without recompiling or creating a new type.• Special kind of static method, called as if it was an instance method on the extended type.• Use site extension – user is in control• Create illusion of adding a method• Not reflectively discoverable• No way to override
    37. 37. Extension methods• Mechnism for interface evolution• Library developer is in control• Main use case: java collections• A.k.a. public defender methods: “if you cannot afford an implementation of this method, one will be provided for you”
    38. 38. Virtual extension methodspublic interface List<E> extends Collections<E> { public void sort(Comparator<? super E> c) default Collections.<E>sort;}public class Collections { public static <T extends Comparable<? super T>> void sort(List<T> list) { ... }}List<Person> jddAtendee = ...jddAtendee.sort(...);
    39. 39. Virtual extension methods• Compiled to regular invokeinterface call• Caller is unaware of special call dispatch• Target method is resolved by JVM at runtime• Adds multiple inheritance of behavior not state!• Changes are (mostly) soruce and binary compatible
    40. 40. Method resolution• Inheritance of methods from classes and interfaces is treated separately• First JVM performs standard method implementation search – from the receiver class upwards through inheritance hierarchy to Object
    41. 41. Method resolution Which method is called? interface Listvoid foo() default; new C().foo(); class D implements List void foo() { ... } class C extends D implements List
    42. 42. Method resolution• List interfaces implemented by C (directly or indirectly) which provide a default for the method in question• Remove all items that are superinterface of any other one from this list• Create a set of distinct defaults provided by interfaces on the list• Resolution is succesful if this set has a single item• Throw a linkage exception otherwise
    43. 43. Method resolution Which method is called? interface Collectionvoid foo() default; new C().foo();interface List implements class C extends D Collection implements Collection void foo() default; class D implements List
    44. 44. Method resolution interface Collection void foo() default; interface List implements interface Queue implements Collection Collection class LinkedList implements List, Queue• When using this method resolution rules diamonds are not a problem (there is no state inheritance!)
    45. 45. Manual method disambiguation• Compile time disambiguation of conflicting defaults is done using new syntax: A.super.method()interface A { void foo() default;}interface B { void foo() default;}class C implements A, B { public void foo() {; }}
    46. 46. Source and binary compatibility Operation Source Compatible Binary Compatible Add default to a method yes yes Remove default from a no no method Add new method with yes yes* default Remove a method with no no default Modify the default yes yes* As long as adding the method itself does not create an invalid overloading
    47. 47. Collection enhancements
    48. 48. Collection enhancementspublic interface Predicate<T> { boolean eval(T t);}public interface Block<T> { void apply(T t);}public interface Mapper<T, U> { U map(T t);}
    49. 49. Iterablepublic interface Iterable<T>{ Iterable<T> filter(Predicate<? super T> predicate) default Iterables.filter; Iterable<T> forEach(Block<? super T> block) default Iterables.forEach; <U> Iterable<U> map(Mapper<? super T, ? extends U> mapper) default; T reduce(T base, Operator<T> reducer) default Iterables.reduce;}
    50. 50. Collectionpublic interface Collection<E> extends Iterable<E> { boolean retainAll(Predicate<? super E> filter) default CollectionHelpers.retainAll; boolean removeAll(Predicate<? super E> filter) default CollectionHelpers.removeAll; void addAll(Iterable<? extends E> source) default CollectionHelpers.addAll;}
    51. 51. Iteratorpublic interface Iterator<E> { boolean hasNext(); E next(); void remove() default Iterators.removeUnsupported;}public final class Iterators { public static <T> void removeUnsupported(Iterator<T> t) { throw new UnsupportedOperationException("remove"); }}
    52. 52. Enumerationinterface Enumeration<E> extends Iterator<E> { boolean hasMoreElements(); E nextElement(); // { return hasMoreElements(); } boolean hasNext() default Enumerations.hasNext; // { return nextElement(); } E next() default;}
    53. 53. Collections enhancementsCollections.sort(list, (p1, p2) -> p1.getName().compareTo(p2.getName()));public void<T, U extends Comparable<? super U>> sortBy(Collection<T> coll, Mapper<T, U> ext); Collections.sortBy(people, Person::getName); people.sortBy(Person::getName);
    54. 54. Development status• Started in december 2009• Compiler implemented as part of an OpenJDK• Early Draft Review recently published ▫• No VM support for extension methods yet
    55. 55. Resources• Compiler prototype binaries available at: ▫• State of the lambda document: ▫ a-state-3.html• Extension methods draft: ▫ er%20Methods%20v3.pdf• Extension methods weaving agent availbale at: ▫
    56. 56. Resources• JDK Enchancement Proposals: ▫• Brian Goetz’s Oracle Blog ▫• Neal Gafter’s blog (interesting for historical purposes) ▫• lambda-dev discussion list ▫