jdt embraces lambda expressions
DESCRIPTION
JDT embraces lambda expressionsTRANSCRIPT
8
8
Srikanth Sankaran
IBM India
Stephan Herrmann
GK Software
BETA_JAVA8
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 3
8Eclipse and Java™ 8
● Java 8 features available in early access builds:
– JSR308 - Type Annotations.
– JEP120 - Repeating Annotations.
– JEP118 - Method Parameter Reflection.
– JSR269 - Pluggable Annotation Processor API & javax.lang.model API enhancements for Java 8.
– Support for “code carrying” interface methods.
● Partial support for
– Lambda Expressions & Method/Constructor references
– Overload resolution & Type inference changes still evolving● had been blocked by incomplete specification until late September
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 4
8Eclipse and Java™ 8
● IDE features available in early access builds:
– Type annotations based static null analysis● substantially complete, open issues exist
– Code completion, code selection/navigation, search engine● for completed features
– Code formatter and code “reconciler”
– IDE enablement support:● AST API's, programmatic AST rewriting API support etc
● Full fledged IDE support work in high gear:
– Early access build refreshes very soon.
● JDT team:
– 12 committers + 1 contributor + 1 GSOC student+ 2 past committers on consulting role.
Java8
Java8
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 6
8New Kinds of Methods
● defender methods
● virtual extension methods
● static interface methods
● default methods
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 7
8New Kinds of Methods
● Code carrying methods in interfaces:
– static methods● non-OO programming even in interfaces
– default methodsprevious names:
● defender methods● virtual extension methods
Those are only 2 kinds :)
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 8
8Default Methods - Intention
● Intention
– support evolution of interfaces in libraries:add methods to an interface w/o breaking implementors
– still legal:
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 9
8 Default Methods - Consequences
● Consequences
– Java 8 has multiple inheritance, sort-of
– but little help for corner cases
Rootm()
Both
Leftm()D
Rightm()D
resolve:
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 10
8 Default Methods - Consequences
● Consequences
– Java 8 has multiple inheritance, sort-of
– but little help for corner cases
Both
Leftm()D
Rightm()
The default method m() inherited from Left conflictswith another method inherited from Right
Advice: Don't!
Default Methods - Consequences
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 12
8Default Methods - Compatibility
● Designed for compatibility during evolution
● For the price of compatibility
– Recipe for disaster:● implement java.util.List → compile against JRE 7 → OK● upgrade to JRE 8 but compile as 1.7
– Undefined compiler behavior● 1.7 compiler cannot handle default methods (from .class)● ecj and javac differ – no plans to assimilate● depending on compiler implementation details, not specification
The type MyList<E> must implement the inherited abstract method Collection<E>.stream()
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 13
8Default Methods - Compatibility
● Designed for compatibility during evolution
● For the price of compatibility
– Recipe for disaster:● implement java.util.List → compile against JRE 7 → OK● upgrade to JRE 8 but compile as 1.7
– Undefined compiler behavior● 1.7 compiler cannot handle default methods (from .class)● ecj and javac differ – no plans to assimilate● depending on compiler implementation details, not specification
The type MyList<E> must implement the inherited abstract method Collection<E>.stream()
Advice: Don't mix -source 1.7 & JRE8!
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 14
8
λ(JSR 335)
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 15
8Introducing Lambda Expressions
● Lambda Expressions, Closures, Anonymous Methods
– what is in a name ?
● A function + “captured state” (may have non-locals)
– accessible even when outside of defining lexical scope
● Theoretical framework dates back several decades:
– Lambda (1930's – Church, Lisp – 1958)
– Closure (1960's - Landin, Scheme - 1975)
– Common idiomatic device in functional programming.
● Paradigm of passing a "code block as data"
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 16
8Java 7 Style of “Code as Data”
● Via anonymous classes
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 17
8Java 7 Style of “Code as Data”
● Via anonymous classes
So if lambda expressions help model "code as data"
are they just old wine in a new bottle?
No!
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 18
8Lambda Expressions
● Eliminate thorny issues with anonymous classes
– Verbose/clunky Syntax
– Scoping● anonymous classes introduce their own scopes● interplay between names in enclosing scope ↔ inherited names
– Capture● can only capture explicitly final outer locals● necessarily capture enclosing class instance (memory leaks)
● Lambdas
– address the above, designed to be flexible & optimizable
– much more pleasing & efficient to program with call backs
– With default methods, enabled Collections overhaul.
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 20
8λ Syntax and Examples
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 21
8Target typing
● Lambda expression is basically
– an anonymous method
– with possibly "captured" enclosing state
● At the grammar level, lambdas are expressions (duh!)
– Can occur anywhere an expression can
– Introduces severe complications in parsing.
● Legally however,
– Lambda needs a context that defines a "target type"
– Everywhere else will have to rejected by the compiler.
– Assignment, initialization, casts, method/ctor invocation, lambda expression body, conditional expressions and return statements are contexts that provide target type.
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 22
8Target Typing Examples
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 23
8Functional Interfaces
● The target type must be a functional interface
● Functional interface
– Declares a single abstract method
– Some methods don't count:● Default & static methods - they are not abstract● May freely redeclare java.lang.Object's methods
– May be tagged with @FunctionalInterface to express intent
● So the lambda object implements the functional interface
● Another way of constructing objects
– apart from the SE7 ways (new, reflection, serialization, clone ...)
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 24
8Lambda Syntax examples
– Parameter types● explicit, or● inferred from target functional interface methods
– Body● expression, or● block.
– ()● can be omitted if a singleton parameter
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 25
8Lambda Syntax examples
– Parameter types● explicit, or● inferred from target functional interface methods
– Body● expression, or● block.
– ()● can be omitted if a singleton parameter
Trade-off between conciseness of expression
vsclarity of code
-in the hands of the programmer
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 26
8Variable capture
● A lambda can refer to enclosing method's locals– Captured state constitutes the "referencing environment"
– Compiler can infer finality
– Captured state is not mutable.
● Properly: capture of "immutable outer local's value"– Mutability of outer locals implies race conditions
– Mutability would necessarily impose serial execution.
– Lambda creation & invocation could be far apart.● may be in different threads, may be after enclosing method return
● This "constraint" actually enables parallelism.
● Enclosing class instance captured only if referred to.
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 27
8Method References
● Similar to lambda expressions
– Require a target type that must be a functional interface
– Serve as instances of the functional interface
– Rather than providing a method body,they refer to an existing method
– Several variants offered.
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 28
8Lambda code generation
● Not lowered into anonymous classes - i.e not just syntactic sugar
● What does the following print ?
● Lambda object creation under the hood:
– Handled by "Lambda metafactory" API in JRE.
– Compilers generates suitable calls to the metafactory.
– Enables various optimizations.
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 29
8Putting it all together
● Here is a nice example from SOTL[*] [*] http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 30
8 JDT features in the works
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 31
8 JDT features in the works
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 32
8 JDT features in the works
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 33
8 JDT features in the works
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 35
8
@(JSR 308)
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 36
8Annotations in more Places
● Java 5: annotate declarations
– ElementType: packages, classes, fields, methods, locals …
● Java 8: annotate types
– ElementType.TYPE_USE
– ElementType.TYPE_PARAMETER
So what?
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 37
8Why Care About Types?
● Type = Constraints on values
To detect anomalies
– missing capability
– incompatible assignment
– undeclared capability
● Constraint checking avoids errors
– No Such Method / Field● Basic statically typed OO
– ClassCastException● Generics
– ??ExceptionMy pet example: NullPointerException
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 38
8Let the Type System Handle Nullity
● Ideally: Java would force explicit choice
– String definitely a String, never null
– String? either a String or null
– Type system ensures: no dereferencing of null
● Nullity as a language feature?
– Heavy weight, incompatible change
– Language change for each new constraint?
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 39
8Pluggable Type System
● Make it easier to add new constraints
– Only one new syntax for all kinds of constraints
● Make it easier to add new type checkers
– Checker Framework (Michael Ernst – U of Washington)
● Examples
– @NonNull
– @Interned equals(== , equals)
– @Immutable value cannot change (Java 5 ?)
– @ReadOnly value cannot change via this reference
– @UI code requires to run on the SWT UI thread
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 40
8
@Target(ElementType.TYPE_USE)@interface NonNull8 {}
@NonNull8 String java8();
Can't Java 5 Do All This?
● We've been lying about the method result– but we can't lie about everything, e.g.:
@Target(ElementType.PARAMETER)@interface NonNull5 {}
void java5(@NonNull5 String arg);
arg is qualified to be non-null
@Target(ElementType.TYPE_USE)@interface NonNull8 {}
void java8(@NonNull8 String arg);
String is qualified to be non-null
String is qualified to be non-null
@Target(ElementType.METHOD)@interface NonNull5 {}
@NonNull5 String java5();
java5 is qualified to be non-null
void printFirstDog(@NonNull List<Dog> dogs) {dogs.get(0).bark();
}
NPE?
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 41
8
void bad(List<String> unknown, List<@Nullable String> withNulls) {@NonNull List<@NonNull String> l1 = new ArrayList<>();l1.add(null);String first = l1.get(0);if (first == null) return;
l1 = unknown;l1 = withNulls;
String canNull = withNulls.get(0);System.out.println(canNull.toUpperCase());
}
@NonNull List<@Nullable String> l2 = new ArrayList<>(); l2 can contain null elements
l1 cannot contain null elements
Annotated Generics
void good() {@NonNull List<@NonNull String> l1 = new ArrayList<>();l1.add("Hello");for (String elem : l1)
System.out.println(elem.toUpperCase());
@NonNull List<@Nullable String> l2 = new ArrayList<>();l2.add(null);for (String unknown : l2)
if (unknown != null)System.out.println(unknown.toUpperCase());
}
Null type mismatch: required '@NonNull String'but the provided value is null
Null type mismatch: required '@NonNull String'but the provided value is null
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 42
8
void bad(List<String> unknown, List<@Nullable String> withNulls) {@NonNull List<@NonNull String> l1 = new ArrayList<>();l1.add(null);String first = l1.get(0);if (first == null) return;
l1 = unknown;l1 = withNulls;
String canNull = withNulls.get(0);System.out.println(canNull.toUpperCase());
}
@NonNull List<@Nullable String> l2 = new ArrayList<>(); l2 can contain null elements
l1 cannot contain null elements
Annotated Generics
void good() {@NonNull List<@NonNull String> l1 = new ArrayList<>();l1.add("Hello");for (String elem : l1)
System.out.println(elem.toUpperCase());
@NonNull List<@Nullable String> l2 = new ArrayList<>();l2.add(null);for (String unknown : l2)
if (unknown != null)System.out.println(unknown.toUpperCase());
}
Null comparison always yields false:The variable first cannot be null at this location
Null comparison always yields false:The variable first cannot be null at this location
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 43
8
void bad(List<String> unknown, List<@Nullable String> withNulls) {@NonNull List<@NonNull String> l1 = new ArrayList<>();l1.add(null);String first = l1.get(0);if (first == null) return;
l1 = unknown;l1 = withNulls;
String canNull = withNulls.get(0);System.out.println(canNull.toUpperCase());
}
@NonNull List<@Nullable String> l2 = new ArrayList<>(); l2 can contain null elements
l1 cannot contain null elements
Annotated Generics
void good() {@NonNull List<@NonNull String> l1 = new ArrayList<>();l1.add("Hello");for (String elem : l1)
System.out.println(elem.toUpperCase());
@NonNull List<@Nullable String> l2 = new ArrayList<>();l2.add(null);for (String unknown : l2)
if (unknown != null)System.out.println(unknown.toUpperCase());
}
Null type safety (type annotations): The expression of type 'List<String>' needs unchecked conversion to conform to '@NonNull List<@NonNull String>'
Null type safety (type annotations): The expression of type 'List<String>' needs unchecked conversion to conform to '@NonNull List<@NonNull String>'
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 44
8
void bad(List<String> unknown, List<@Nullable String> withNulls) {@NonNull List<@NonNull String> l1 = new ArrayList<>();l1.add(null);String first = l1.get(0);if (first == null) return;
l1 = unknown;l1 = withNulls;
String canNull = withNulls.get(0);System.out.println(canNull.toUpperCase());
}
@NonNull List<@Nullable String> l2 = new ArrayList<>(); l2 can contain null elements
l1 cannot contain null elements
Annotated Generics
void good() {@NonNull List<@NonNull String> l1 = new ArrayList<>();l1.add("Hello");for (String elem : l1)
System.out.println(elem.toUpperCase());
@NonNull List<@Nullable String> l2 = new ArrayList<>();l2.add(null);for (String unknown : l2)
if (unknown != null)System.out.println(unknown.toUpperCase());
}
Null type mismatch (type annotations):required '@NonNull List<@NonNull String>'but this expression has type 'List<@Nullable String>'
Null type mismatch (type annotations):required '@NonNull List<@NonNull String>'but this expression has type 'List<@Nullable String>'
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 45
8
void bad(List<String> unknown, List<@Nullable String> withNulls) {@NonNull List<@NonNull String> l1 = new ArrayList<>();l1.add(null);String first = l1.get(0);if (first == null) return;
l1 = unknown;l1 = withNulls;
String canNull = withNulls.get(0);System.out.println(canNull.toUpperCase());
}
@NonNull List<@Nullable String> l2 = new ArrayList<>(); l2 can contain null elements
l1 cannot contain null elements
Annotated Generics
void good() {@NonNull List<@NonNull String> l1 = new ArrayList<>();l1.add("Hello");for (String elem : l1)
System.out.println(elem.toUpperCase());
@NonNull List<@Nullable String> l2 = new ArrayList<>();l2.add(null);for (String unknown : l2)
if (unknown != null)System.out.println(unknown.toUpperCase());
}
Potential null pointer access: The variable canNull may be null at this location
Potential null pointer access: The variable canNull may be null at this location
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 47
8Framework Development (1)
● So you want to be smart:
● But will clients like it?
● If thou usest annotations know thy co/contravariance– @Nullable parameter is irreversible
– Design bug in guava's Predicate / Function
public interface ILib<E> {@NonNull E work(@Nullable E e);
}
public class LibImpl implements ILib<String> {
@Overridepublic @Nullable String work(@NonNull String e) { return null; }
}
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 48
8Framework Development (2)
class ToString implements Function<@NonNull Object, @Nullable String> {@Overridepublic @Nullable String apply(@NonNull Object o) { return o.toString(); }
}
● Avoid overspecification, make interfaces null-generic:
● Let clients decide
● Putting the pieces together
public interface Function<I,O> {O apply(I in);
}
<@NonNull I, @Nullable O> Collection<O> map1(Collection<I> in, Function<I, O> f) { … }
<@Nullable I, @NonNull O> Collection<O> map2(Collection<I> in, Function<I, O> f) { … }
...List<@NonNull Object> in = new ArrayList<>();Collection<@Nullable String> out = map1(in, new ToString());
No NPE!
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 49
8Caveat: Arrays
● Semantics are changing from Java 7 to Java 8
void test (@NonNull String [] stringsOrNulls) {System.out.println(stringsOrNulls[0]);
}
void test (@NonNull String [] stringsOrNulls) {System.out.println(stringsOrNulls[0]);
}
array of nonnull elements the array can still be null ⇒ NPE
void test (String @NonNull [] stringsOrNulls) {System.out.println(stringsOrNulls[0]);
}
nonnull array NPE- safe (but may print “null”)
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 50
8 Status: Annotated Type Analysis
● Implemented EA: @NonNull, @Nullable
– Much analysis already performed● known & unknown bugs
– Editor may show more bogus errors● Project > Clean and Problems View
● Planned: @Uninterned
● Proposed: @UiEffect, @Ui …
– by [Colin S. Gordon, Werner Dietl, Michael D. Ernst, and Dan Grossman]
– SWT: bye, bye, “Invalid thread access”
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 51
8Status: Type Annotations
● Supported by
– Compiler
– DOM AST
– APT
● Work in progress
– respect during
● Not yet supported by
– Java model
CtrlCtrl CtrlCtrl 1 CtrlAlt T
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 52
8TypeBinding Backstage Story
● Type bindings are “interned”
– OK to use ==
● Broken by encoding type annotations in type bindings
● Solution
– Find/replace == comparisons for T <: TypeBinding
– Tweak our compiler to do this
– Plan: publish the tweak, controlled by @Uninterned
aka “Symbol”
Srikanth Sankaran, Stephan Herrmann: Eclipse and Java 8 - EclipseCon Europe 2013 # 53
8
Dramatis personæ
● Jay Arthanareeswaran● Anirban Chakarborty● Manoj Palat● Shankha Banerjee● Manju Mathew● Noopur Gupta● Deepak Azad● Srikanth Sankaran
● Olivier Thomann● Andy Clement● Michael Rennie
● Jesper S. Møller
● Walter Harley
● Stephan Herrmann
● Dani Megert● Markus Keller
● Early Access:
– http://wiki.eclipse.org/JDT_Core/Java8
● We invite you to test - defect reports welcome !