Lift off with Groovy 2 at JavaOne 2013
-
Upload
guillaume-laforge -
Category
Technology
-
view
1.808 -
download
1
description
Transcript of Lift off with Groovy 2 at JavaOne 2013
© 2013 Guillaume Laforge. All rights reserved. Do not distribute without permission.
Guillaume Laforge @glaforge
Lift-off with Groovy 2 ...and beyond!
© 2013 Guillaume Laforge. All rights reserved. Do not distribute without permission.
Guillaume Laforge @glaforge
Lift-off with Groovy 2 ...and beyond!
Guillaume Laforge @glaforge
http://glaforge.appspot.com http://gplus.to/glaforge
Guillaume Laforge @glaforge
http://glaforge.appspot.com http://gplus.to/glaforge
Presentation will be uploaded tohttps://speakerdeck.com/glaforge
A dynamic language,optionally typed
Groovy
...statically type checkedand compiled as needed
Groovy
Syntax deriving from Java, thus easy to learn
Groovy
million downloadsin 2012
1.7
10
A blossomingEcosystem
GVM
Let’s start the engine
ModularityJava 7: Project Coin & invoke dynamicStatic type checking & compilation
Modularity
« Not everybody needs everything,all the time, at the same time! »
Groovy modularity
• The « groovy-all » weighted... 6 MB !
• In addition to the language, we have APIs:– template engine, Ant task scripting, Swing UI builder,
JMX builder...
• We want a lighter « core »– with APIs in the form of modules
• Ability to wire in « extension methods »
16
The new JARs
• One smaller core JAR of 3 MB
• Modules
– console– docgenerator– groovydoc– groovysh– ant– bsf
– jsr-223– jmx– sql– swing– servlet– templates
– test– testng– json– xml
17
The new JARs
• One smaller core JAR of 3 MB
• Modules
– console– docgenerator– groovydoc– groovysh– ant– bsf
– jsr-223– jmx– sql– swing– servlet– templates
– test– testng– json– xml
17
« Let’s go shopping »
Extension modules
• Create your own extension module– contribute instance methods
package foo
class StringExtension { static introduces(String self, String name) { "Hi ${name), I’m ${self}" }}
// usage: "Guillaume".introduces("Cédric")
19
Extension modules
• Create your own extension module– contribute instance methods
package foo
class StringExtension { static introduces(String self, String name) { "Hi ${name), I’m ${self}" }}
// usage: "Guillaume".introduces("Cédric")
Same structure as categories
19
Extension modules
• Create your own extension module– contribute static methods
20
package foo
class StaticStringExtension { static hi(String self) { "Hi!" }}// usage: String.hi()
Extension module descriptor
• META-INF/– services/
• org.codehaus.groovy.runtime.ExtensionModule
moduleName = stringExtensionsmoduleVersion = 1.0// comma separated list of FQN class namesextensionClasses = foo.StringExtension// comma separated list of FQN class namesstaticExtensionClasses = foo.StaticStringExtension
21
Java 7 theme
« Project Coin » syntaxInvoke Dynamic support
Binary literals
• In addition to decimal, octal and hexa• A new binary representation:
int x = 0b10101111assert x == 175 byte aByte = 0b00100001assert aByte == 33 int anInt = 0b1010000101000101assert anInt == 41285
23
Underscores in literals
• Use underscores in number literals
long creditCardNumber = 1234_5678_9012_3456Llong socialSecurityNumbers = 999_99_9999Lfloat monetaryAmount = 12_345_132.12long hexBytes = 0xFF_EC_DE_5Elong hexWords = 0xFFEC_DE5Elong maxLong = 0x7fff_ffff_ffff_ffffLlong alsoMaxLong = 9_223_372_036_854_775_807Llong bytes = 0b11010010_01101001_10010100_10010010
25
Multi-catch exception blocks
• A single catch block to catch several exceptions at once, rather than duplicating blocks
try { /* ... */} catch(IOException | NullPointerException e) { /* un seul bloc */}
26
Woot!
JDK 7 Invoke Dynamic support
• A « flag » to compile with « indy »– we might propose a backport for JDK < 7
• Avantages– more runtime performance
•well... in theory...– In the long term, we might replace
•« call site caching » ➔ MethodHandles•« metaclass registry » ➔ ClassValues
– and the JIT « inlines » code more easily
28
A « static » theme
Static type checkingStatic compilation
Static type checking
• Goal: make the compiler grumpy!
– throw errors at compile-time• rather than at runtime
30
We don’t need dynamic features
all the time!
We don’t need dynamic features
all the time!
Nah !
Static type checking
• A « grumpy » compiler should...
– say when there’s a typoin a method or variable name
– complain when a non-existent method is called
– or on bad assignments or use a bad return type
32
Static type checking
• The compiler should infer types...
– less explicit types and casts
– fine grained type inference•« flow typing »•« lowest upper bound »
33
Static type checking
• But the compiler should understand extension methods
– allows a good level of dynamism, despite the additional restrictions
34
Typos
import groovy.transform.TypeChecked void method() {} @TypeChecked test() { // Cannot find matching method metthhoood() metthhoood() def name = "Guillaume" // variable naamme is undeclared println naamme}
35
Typos
import groovy.transform.TypeChecked void method() {} @TypeChecked test() { // Cannot find matching method metthhoood() metthhoood() def name = "Guillaume" // variable naamme is undeclared println naamme}
Compilation error
35
Typos
import groovy.transform.TypeChecked void method() {} @TypeChecked test() { // Cannot find matching method metthhoood() metthhoood() def name = "Guillaume" // variable naamme is undeclared println naamme}
Compilation error
Compilation error
35
Typos
import groovy.transform.TypeChecked void method() {} @TypeChecked test() { // Cannot find matching method metthhoood() metthhoood() def name = "Guillaume" // variable naamme is undeclared println naamme}
Compilation error
Compilation error
Annotation at the method or class level
35
Wrong variable assignments
// cannot assign value of type... to variable...int x = new Object()Set set = new Object() String[] strings = ['a','b','c']int str = strings[0] // cannot find matching method plus()int i = 0i += '1'
36
Wrong variable assignments
// cannot assign value of type... to variable...int x = new Object()Set set = new Object() String[] strings = ['a','b','c']int str = strings[0] // cannot find matching method plus()int i = 0i += '1'
Compilation error
36
Wrong variable assignments
// cannot assign value of type... to variable...int x = new Object()Set set = new Object() String[] strings = ['a','b','c']int str = strings[0] // cannot find matching method plus()int i = 0i += '1'
Compilation error
Compilation error
36
Wrong variable assignments
// cannot assign value of type... to variable...int x = new Object()Set set = new Object() String[] strings = ['a','b','c']int str = strings[0] // cannot find matching method plus()int i = 0i += '1'
Compilation error
Compilation error
Compilation error
36
Wrong return type
// checks if/else branch return values@TypeCheckedint method() { if (true) { 'String' } else { 42 }}// works for switch/case & try/catch/finally // transparent toString() implied@TypeCheckedString greeting(String name) { def sb = new StringBuilder() sb << "Hi " << name}
37
Wrong return type
// checks if/else branch return values@TypeCheckedint method() { if (true) { 'String' } else { 42 }}// works for switch/case & try/catch/finally // transparent toString() implied@TypeCheckedString greeting(String name) { def sb = new StringBuilder() sb << "Hi " << name}
Compilation error
37
Wrong return type
// checks if/else branch return values@TypeCheckedint method() { if (true) { 'String' } else { 42 }}// works for switch/case & try/catch/finally // transparent toString() implied@TypeCheckedString greeting(String name) { def sb = new StringBuilder() sb << "Hi " << name}
Compilation error
In the end, call StringBuilder’s toString()
37
Type inference
@TypeChecked test() { def name = " Guillaume " // String type infered (even inside GString) println "NAME = ${name.toUpperCase()}" // Groovy GDK method support // (GDK operator overloading too) println name.trim() int[] numbers = [1, 2, 3] // Element n is an int for (int n in numbers) { println n }}
38
Type inference
@TypeChecked test() { def name = " Guillaume " // String type infered (even inside GString) println "NAME = ${name.toUpperCase()}" // Groovy GDK method support // (GDK operator overloading too) println name.trim() int[] numbers = [1, 2, 3] // Element n is an int for (int n in numbers) { println n }}
Variable optionally typed
38
Type inference
@TypeChecked test() { def name = " Guillaume " // String type infered (even inside GString) println "NAME = ${name.toUpperCase()}" // Groovy GDK method support // (GDK operator overloading too) println name.trim() int[] numbers = [1, 2, 3] // Element n is an int for (int n in numbers) { println n }}
Variable optionally typed
Type String infered
38
Type inference
@TypeChecked test() { def name = " Guillaume " // String type infered (even inside GString) println "NAME = ${name.toUpperCase()}" // Groovy GDK method support // (GDK operator overloading too) println name.trim() int[] numbers = [1, 2, 3] // Element n is an int for (int n in numbers) { println n }}
Variable optionally typed
trim() method added dynamically by Groovy
Type String infered
38
Type inference
@TypeChecked test() { def name = " Guillaume " // String type infered (even inside GString) println "NAME = ${name.toUpperCase()}" // Groovy GDK method support // (GDK operator overloading too) println name.trim() int[] numbers = [1, 2, 3] // Element n is an int for (int n in numbers) { println n }}
Variable optionally typed
Array element type inferred
trim() method added dynamically by Groovy
Type String infered
38
Mix dynamic & statically checked code
@TypeCheckedString greeting(String name) { // call method with dynamic behavior // but with proper signature generateMarkup(name.toUpperCase())} // usual dynamic behaviorString generateMarkup(String name) { def sw = new StringWriter() new MarkupBuilder(sw).html { body { div name } } sw.toString()}
39
Mix dynamic & statically checked code
@TypeCheckedString greeting(String name) { // call method with dynamic behavior // but with proper signature generateMarkup(name.toUpperCase())} // usual dynamic behaviorString generateMarkup(String name) { def sw = new StringWriter() new MarkupBuilder(sw).html { body { div name } } sw.toString()}
Statically checked
39
Mix dynamic & statically checked code
@TypeCheckedString greeting(String name) { // call method with dynamic behavior // but with proper signature generateMarkup(name.toUpperCase())} // usual dynamic behaviorString generateMarkup(String name) { def sw = new StringWriter() new MarkupBuilder(sw).html { body { div name } } sw.toString()}
Statically checked
Dynamic
39
Instanceof checks
@TypeChecked void test(Object val) {
if (val instanceof String) { println val.toUpperCase() } else if (val instanceof Number) { println "X" * val.intValue() }}
40
Instanceof checks
@TypeChecked void test(Object val) {
if (val instanceof String) { println val.toUpperCase() } else if (val instanceof Number) { println "X" * val.intValue() }}
No need for casts
40
Instanceof checks
@TypeChecked void test(Object val) {
if (val instanceof String) { println val.toUpperCase() } else if (val instanceof Number) { println "X" * val.intValue() }}
No need for casts
No need for casts
40
Instanceof checks
@TypeChecked void test(Object val) {
if (val instanceof String) { println val.toUpperCase() } else if (val instanceof Number) { println "X" * val.intValue() }}
No need for casts
No need for castsUnderstand GDK’s method:
String#multiply(int)
40
Lowest Upper Bound
• The smallest common « super » type– might be virtual (« non-denotable »)
@TypeChecked test() { // an integer and a BigDecimal return [1234, 3.14]}
41
Lowest Upper Bound
• The smallest common « super » type– might be virtual (« non-denotable »)
@TypeChecked test() { // an integer and a BigDecimal return [1234, 3.14]}
Infered type:List<T extends Number & Comparable & Serializable>
41
Flow typing
• Static type checking « follows » the type of values assigned into variables
@TypeChecked test() { def var = 123 // int infered int x = var // var is an int var = "123" // assign a String into var
x = var.toInteger() // no cast needed
var = 123 x = var.toUpperCase() // error, var is an int !}
42
Not really clean, your code!
Not really clean, your code!
Grmmpf...no!
Static type checking and dynamic code
•Type checking happens at compile-time– @TypeChecked doesn’t change behavior!
• do not confound with static compilation
• Most dynamic features can’t be checked– metaclass changes, categories...– dynamic variables from the « script binding »
• But compile-time metaprogramming OK– if enough type information is available
44
But if it ain’t dynamic, can we compile
it statically?
But if it ain’t dynamic, can we compile
it statically?
But of course!!!
Static compilation
• Given the code is statically type checked, lots of type information was infered...so we can as well compile statically !
– ie. generate the same bytecode as javac
• Also interesting when stuck on JDK < 7to gain performance improvements
46
Avantages of static compilation
• We gain:– type safety
• thanks to static type checking –the compiler builds upon it
– better performance• close to Java’s performance
– code immune to « monkey patching »•dynamic metaprogramming can interfere with your framework’s code
– smaller generated bytecode
47
I canz do what I want wiz your code
I canz do what I want wiz your code
Niark !
Drawbacks for static compilation
• We lose...
– Some dynamic features• metaclass changes, categories
– Method « dynamic dispatch » can differ• but thanks to type inference, it’s as close as «classical» Groovy as possible
49
Mix statically compiled code with dynamic
@CompileStaticString greeting(String name) { // call method with dynamic behavior // but with proper signature generateMarkup(name.toUpperCase())} // usual dynamic behaviorString generateMarkup(String name) { def sw = new StringWriter() new MarkupBuilder(sw).html { body { div name } } sw.toString()}
50
Mix statically compiled code with dynamic
@CompileStaticString greeting(String name) { // call method with dynamic behavior // but with proper signature generateMarkup(name.toUpperCase())} // usual dynamic behaviorString generateMarkup(String name) { def sw = new StringWriter() new MarkupBuilder(sw).html { body { div name } } sw.toString()}
Statically compiled
50
Mix statically compiled code with dynamic
@CompileStaticString greeting(String name) { // call method with dynamic behavior // but with proper signature generateMarkup(name.toUpperCase())} // usual dynamic behaviorString generateMarkup(String name) { def sw = new StringWriter() new MarkupBuilder(sw).html { body { div name } } sw.toString()}
Statically compiled
Dynamic
50
Mix statically compiled code with dynamic
@CompileStaticString greeting(String name) { // call method with dynamic behavior // but with proper signature generateMarkup(name.toUpperCase())} // usual dynamic behaviorString generateMarkup(String name) { def sw = new StringWriter() new MarkupBuilder(sw).html { body { div name } } sw.toString()}
Statically compiled
Dynamic
Call a method with
dynamic content
50
Mix statically compiled code with dynamic
@CompileStaticString greeting(String name) { // call method with dynamic behavior // but with proper signature generateMarkup(name.toUpperCase())} // usual dynamic behaviorString generateMarkup(String name) { def sw = new StringWriter() new MarkupBuilder(sw).html { body { div name } } sw.toString()}
Statically compiled
Dynamic
Call a method with
dynamic content
Method signatures are a contract!
50
What about performance?
• Comparisons between:
– Java
– Groovy•with static compilation (Groovy 2.0)•with primitive type optimization (Groovy 1.8)•no optimization (Groovy 1.7)
51
What about performance?
Fibonacci Pi (π) quadrature
Binarytrees
Java
Staticcompilation
Primitive optimizations
No prim.optimizations
191 ms 97 ms 3.6 s
197 ms 101 ms 4.3 s
360 ms 111 ms 23.7 s
2590 ms 3220 ms 50.0 s1.7
1.8
2.x
52
...and now, ontoGroovy 2.1
Complete Invoke Dynamic supportMeta-annotationsAdvanced compiler configurationType checker extensions
Invoke Dynamic
Complete support of Invoke Dynamic
Meta-annotations
One annotationto rule them all!
Meta-annotations
• Create meta-annotations which combine and/or parameterize other annotations
• And which work with AST transformations
56
Meta-annotations
@Immutable@ToString(excludes = ["age"])@AnnotationCollector@interface MyAlias {}
57
Meta-annotations
@Immutable@ToString(excludes = ["age"])@AnnotationCollector@interface MyAlias {}
Collected annotations
57
Meta-annotations
@Immutable@ToString(excludes = ["age"])@AnnotationCollector@interface MyAlias {}
Collected annotations
The collector
57
Meta-annotations
@Immutable@ToString(excludes = ["age"])@AnnotationCollector@interface MyAlias {}
Collected annotations
The collector
Your own annotation
alias
57
Meta-annotations
@Immutable@ToString(excludes = ["age"])@AnnotationCollector@interface MyAlias {}
@MyAliasclass Person { String name int age}
Collected annotations
The collector
Your own annotation
alias
57
Meta-annotations
@Immutable@ToString(excludes = ["age"])@AnnotationCollector@interface MyAlias {}
@MyAliasclass Person { String name int age}
Collected annotations
The collector
Your own annotation
aliasUse your meta-
annotation
57
@DelegatesTo annotation
Richer tooling supportfor Domain-Specific Languages
@DelegatesTo annotation
• Static type checking works fine with a certain range of DSLs– « command chains », extension methods...
• But less for DSLs using closure delegation– often used by DSLs like in Gradle
task copyTask(type: Copy) { from 'src/main/webapp' into 'build/explodedWar'}
59
@DelegatesTo annotation
exec(spec) { foo()}
60
@DelegatesTo annotationclass ExecSpec { void foo()}
exec(spec) { foo()}
60
@DelegatesTo annotationclass ExecSpec { void foo()}
void exec(ExecSpec sp, Closure c) { c.delegate = sp c()}
exec(spec) { foo()}
60
@DelegatesTo annotationclass ExecSpec { void foo()}
void exec(ExecSpec sp, Closure c) { c.delegate = sp c()}
exec(spec) { foo()}
The static type checker doesn’t know about method foo()
60
@DelegatesTo annotationclass ExecSpec { void foo()}
void exec(ExecSpec sp, Closure c) { c.delegate = sp c()}
exec(spec) { foo()}
Annotate with @DelegatesTo(ExecSpec)
The static type checker doesn’t know about method foo()
60
@DelegatesTo annotation
• With another delegation strategy
void exec(ExecSpec sp, Closure c) { c.delegate = sp c.resolveStrategy = DELEGATE_FIRST c()}
61
@DelegatesTo annotation
• With another delegation strategy
void exec(ExecSpec sp, Closure c) { c.delegate = sp c.resolveStrategy = DELEGATE_FIRST c()}
Annotate with@DelegatesTo(value = ExecSpec,
strategy = DELEGATE_FIRST)
61
@DelegatesTo annotation
• Very interesting for DSLs using closure’s delegation strategy
• Excellent for...– documenting your APIs– the integration within the IDE
• code completion, code navigation
– works well with static type checking and static compilation
62
Extend the static type checker
To go even further than Java itself !
Extend the static type checker
• Extend the type checker to make it smarter!– even smarter than Java’s! :-)
• By creating your own extension
@TypeChecked(extensions = 'MyExtension.groovy')void exec() { // code to be further checked...}
64
Extend the static type checker
• Extend the type checker to make it smarter!– even smarter than Java’s! :-)
• By creating your own extension
@TypeChecked(extensions = 'MyExtension.groovy')void exec() { // code to be further checked...}
We could use a meta-annotation
64
Extend the static type checker
• Help the static type checker when...
– impossible to infer types– no matching method found– no matching attribute found– on wrong variable assignment– ...
65
Extend the static type checker
• Your extension has access to an event-oriented API
66
• onMethodSelection
• afterMethodCall• beforeMethodCall
• afterVisitMethod• beforeVisitMethod
• methodNotFound• unresolvedVariable• unresolvedProperty• unresolvedAttribute
• incompatibleAssignment
Extend the static type checker
onMethodSelection { expr, method -‐> ... }afterMethodCall { mc -‐> ... }unresolvedVariable { var -‐> ... }methodNotFound { receiver, name, argList, argTypes, call -‐> ... }incompatibleAssignment { lhsType, rhsType, expr -‐> ... }
67
Extend the static type checker
onMethodSelection { expr, method -‐> ... }afterMethodCall { mc -‐> ... }unresolvedVariable { var -‐> ... }methodNotFound { receiver, name, argList, argTypes, call -‐> ... }incompatibleAssignment { lhsType, rhsType, expr -‐> ... }
MyExtension.groovy
67
Extend the static type checker
onMethodSelection { expr, method -‐> ... }afterMethodCall { mc -‐> ... }unresolvedVariable { var -‐> ... }methodNotFound { receiver, name, argList, argTypes, call -‐> ... }incompatibleAssignment { lhsType, rhsType, expr -‐> ... }
MyExtension.groovy
Learn your Groovy AST!
67
Extend the static type checker
onMethodSelection { expr, method -‐> ... }afterMethodCall { mc -‐> ... }unresolvedVariable { var -‐> ... }methodNotFound { receiver, name, argList, argTypes, call -‐> ... }incompatibleAssignment { lhsType, rhsType, expr -‐> ... }
MyExtension.groovy
Learn your Groovy AST!
No need to be pre-compiled
67
Extend the static type checker
• A few examples
– check that a string is a valid SQL query
– check the arguments and types of sprintf() method calls so they match the pattern
68
Compiler configuration
Custom base script classConfiguration script
Configuration DSL
Compiler customization
• Groovy 1.8 introduced « customizers »– add imports transparently– apply AST transformations by default– filter / secure scripts
• With the « static type checker » and « static compilation », we were asked if we could apply them by default
70
Compiler customization
• New options
– --basescript to define a base script class for your scripts
– --configscript to indicate a script to configure the CompilerConfiguration object
71
Compiler customization
• Add the @ToString AST transformation
import groovy.transform.ToStringimport org.codehaus.groovy.control.customizers .ASTTransformationCustomizer
configuration.addCompilationCustomizer( new ASTTransformationCustomizer(ToString))
72
Compiler customization
• Add the @ToString AST transformation
import groovy.transform.ToStringimport org.codehaus.groovy.control.customizers .ASTTransformationCustomizer
configuration.addCompilationCustomizer( new ASTTransformationCustomizer(ToString))
CompilerConfiguration instance,injected by default
72
Compiler customization
• A small DSL to configure the customization
configuration.customizers { // apply to MyBean.groovy source(basename: 'MyBean') { ast(ToString) }}
73
Compiler customization
• A small DSL to configure the customization
configuration.customizers { // apply to MyBean.groovy source(basename: 'MyBean') { ast(ToString) }}
configuration.customizers { // apply to *.gbean files source(extension: '.gbean') { ast(ToString) }}
73
Compiler customization
• A small DSL to configure the customization
configuration.customizers { // apply to MyBean.groovy source(basename: 'MyBean') { ast(ToString) }}
configuration.customizers { // apply to *.gbean files source(extension: '.gbean') { ast(ToString) }}
configuration.customizers { // custom filter logic source(unitValidator: { unit -‐> ... }) { ast(ToString) imports { staticStar 'java.lang.Math' } }}
73
To learn more...Groovy 2.0http://groovy.codehaus.org/Groovy+2.0+release+notes
Groovy 2.1http://groovy.codehaus.org/Groovy+2.1+release+notes
And what’s next?Groovy 2.2, 2.3 & 3 !
New « MOP »New Grammar with Antlr v4Java 8 Lambdas support
A few words about the roadmap
2014 2014 20132012
Groovy 2.1
Groovy 2.0Groovy 2.0 Groovy 2.2
Groovy 2.3
76
Groovy 3.0
A few words about the roadmap
2014 2014 20132012
Groovy 2.1
Groovy 2.0Groovy 2.0 Groovy 2.2
Groovy 2.3
76
Groovy 3.0
A few words about the roadmap
2014 2014 20132012
Groovy 2.1
Groovy 2.0Groovy 2.0 Groovy 2.2
Groovy 2.3
76
Groovy 3.0
Groovy 2.2
Implicit closure coercion@Memoized transformation
DelegatingScript base script class
Implicit closure coercion
78
Implicit closure coercion
interface Predicate<T> { boolean test(T t)}
List<T> filter(Predicate<T> p)
78
Implicit closure coercion
interface Predicate<T> { boolean test(T t)}
List<T> filter(Predicate<T> p)
Given a predicate & a List method to filter according to that predicate...
78
Implicit closure coercion
interface Predicate<T> { boolean test(T t)}
List<T> filter(Predicate<T> p)
list.filter((it) -‐> it.age > 18)
Given a predicate & a List method to filter according to that predicate...
78
Implicit closure coercion
interface Predicate<T> { boolean test(T t)}
List<T> filter(Predicate<T> p)
list.filter((it) -‐> it.age > 18)
Given a predicate & a List method to filter according to that predicate...
Java 8 lambdas can be more concise than Groovy!
78
Implicit closure coercion
interface Predicate<T> { boolean test(T t)}
List<T> filter(Predicate<T> p)
list.filter((it) -‐> it.age > 18)
list.filter({ it.age > 18 } as Predicate)
Given a predicate & a List method to filter according to that predicate...
Java 8 lambdas can be more concise than Groovy!
78
Implicit closure coercion
interface Predicate<T> { boolean test(T t)}
List<T> filter(Predicate<T> p)
list.filter((it) -‐> it.age > 18)
list.filter { it.age > 18 }
Given a predicate & a List method to filter according to that predicate...
Java 8 lambdas can be more concise than Groovy!
78
Implicit closure coercion
interface Predicate<T> { boolean test(T t)}
List<T> filter(Predicate<T> p)
list.filter((it) -‐> it.age > 18)
list.filter { it.age > 18 }
Given a predicate & a List method to filter according to that predicate...
Java 8 lambdas can be more concise than Groovy!
When no ambiguity, make coercion implicit!
78
Implicit closure coercion
interface Predicate<T> { boolean test(T t)}
List<T> filter(Predicate<T> p)
list.filter((it) -‐> it.age > 18)
list.filter { it.age > 18 }
Given a predicate & a List method to filter according to that predicate...
Java 8 lambdas can be more concise than Groovy!
When no ambiguity, make coercion implicit!
Go beyond Java, by making it work on abstract classes too
78
DelegatingScript base script class
• Special base script class to delegate method calls and property accesses to a delegatee
79
DelegatingScript base script class
• Special base script class to delegate method calls and property accesses to a delegatee
Handy for DSLs!
79
DelegatingScript base script class
• Special base script class to delegate method calls and property accesses to a delegatee
Handy for DSLs!
name = "Guillaume"sayHi()
79
DelegatingScript base script class
• Special base script class to delegate method calls and property accesses to a delegatee
class Person { String name
void sayHi() { println "Hi $name" }}
Handy for DSLs!
name = "Guillaume"sayHi()
79
DelegatingScript base script class
• Special base script class to delegate method calls and property accesses to a delegatee
class Person { String name
void sayHi() { println "Hi $name" }}
Handy for DSLs!
name = "Guillaume"sayHi()
Use Person’s name property
79
DelegatingScript base script class
• Special base script class to delegate method calls and property accesses to a delegatee
class Person { String name
void sayHi() { println "Hi $name" }}
Handy for DSLs!
name = "Guillaume"sayHi()
Use Person’s name property
Call Person#sayHi()
79
DelegatingScript base script class
• Integration example:
def cc = new CompilerConfiguration()cc.scriptBaseClass = DelegatingScript.class.name
def sh = new GroovyShell(cc)def script = sh.parse(file)
def p = new Person()script.setDelegate(p)script.run()
assert p.name == "Guillaume"
80
DelegatingScript base script class
• Integration example:
def cc = new CompilerConfiguration()cc.scriptBaseClass = DelegatingScript.class.name
def sh = new GroovyShell(cc)def script = sh.parse(file)
def p = new Person()script.setDelegate(p)script.run()
assert p.name == "Guillaume"
Specify DelegatingScript base class
80
DelegatingScript base script class
• Integration example:
def cc = new CompilerConfiguration()cc.scriptBaseClass = DelegatingScript.class.name
def sh = new GroovyShell(cc)def script = sh.parse(file)
def p = new Person()script.setDelegate(p)script.run()
assert p.name == "Guillaume"
Specify DelegatingScript base class
Parse the script
80
DelegatingScript base script class
• Integration example:
def cc = new CompilerConfiguration()cc.scriptBaseClass = DelegatingScript.class.name
def sh = new GroovyShell(cc)def script = sh.parse(file)
def p = new Person()script.setDelegate(p)script.run()
assert p.name == "Guillaume"
Specify DelegatingScript base class
Parse the script
Define the delegate
80
DelegatingScript base script class
• Integration example:
def cc = new CompilerConfiguration()cc.scriptBaseClass = DelegatingScript.class.name
def sh = new GroovyShell(cc)def script = sh.parse(file)
def p = new Person()script.setDelegate(p)script.run()
assert p.name == "Guillaume"
Specify DelegatingScript base class
Parse the script
Define the delegate
Run the script
80
DelegatingScript base script class
• Integration example:
def cc = new CompilerConfiguration()cc.scriptBaseClass = DelegatingScript.class.name
def sh = new GroovyShell(cc)def script = sh.parse(file)
def p = new Person()script.setDelegate(p)script.run()
assert p.name == "Guillaume"
Specify DelegatingScript base class
Parse the script
Define the delegate
Run the script
Be Happy!80
groovysh doc command
81
groovysh doc command
Launches your browser with the JavaDoc and GDK doc of the class
81
groovysh code completion
82
groovysh code completion
Import completion
82
groovysh code completion
Import completion
Method call completion
82
@Memoized transformation
• Piggypack on Closure’s own memoization capabilities, but applied to methods
@Memoized int expensiveOp(int a, int b) { sleep 1000 return a + b}// one second to returnexpensiveOp(1, 2) // immediate result returnedexpensiveOp(1, 2)
83
Miscelanous improvements
• Precompiled type checking extensions
• Further tweaks to Groovysh with code completion, better error reporting...
• Better syntax highlighting in Groovy Console
• Various dependency upgrades (Gradle, Ant)
@TypeChecked(extensions = 'fqn.MyExtension')
84
Additional GDK methods...
• groupBy() on arrays
• combinations(Closure)
• collectMany() on Iterables
• JsonSlurper’s parse(File) and parse(URL)
assert [[2, 3], [4, 5, 6]] .combinations { x, y -‐> x*y } == [8, 12, 10, 15, 12, 18]
85
Likely inGroovy 2.3
TraitsGroovyDoc rewrite
New documentation & website
Trait implementation
87
Trait implementation
trait FlyingAbility { String fly() { "I believe I can fly!" }}
87
Trait implementation
trait FlyingAbility { String fly() { "I believe I can fly!" }}
A trait keyword applying the @Trait transformation
87
Trait implementation
trait FlyingAbility { String fly() { "I believe I can fly!" }}
A trait keyword applying the @Trait transformation
class Car implements FlyingAbility {}
87
Trait implementation
trait FlyingAbility { String fly() { "I believe I can fly!" }}
A trait keyword applying the @Trait transformation
class Car implements FlyingAbility {}
A class «implements» the trait
87
Trait implementation
trait FlyingAbility { String fly() { "I believe I can fly!" }}
A trait keyword applying the @Trait transformation
class Car implements FlyingAbility {}
A class «implements» the trait
def c = new Car()assert c.fly() == "I believe I can fly!"
87
GroovyDoc rewrite
88
GroovyDoc rewrite
GroovyDoc != Sexy Doc
88
New documentation and website
• New reference documentation and guides using AsciiDoctor
• New website with a refreshed skin and the new content
89
Groovy 3
New MOPNew Antlr v4 grammarJDK 8 lambda support
MOP
2
Antlr 4grammar
λJDK
8
Summary
• A very rich and blossoming ecosystem•Groovy 2.0
– more modular– a static theme
• static type checking• static compilation
– JDK 7 theme• Invoke Dynamic support• Project Coin syntax enhancements
95
Summary
•Groovy 2.1– Invoke Dynamic support completed– @DelegatesTo annotation– type checker extensions for DSLs– meta-annotations
96
Summary
• Groovy 2.2 – implicit closure coercion– @Memoized transformation– DelegatingScript for script DSLs– groovysh improvements
97
Summary
• Groovy 2.3– traits– new GroovyDoc– new documentation– new website
98
Summary
• Groovy 3– a new MOP (Meta-Object Protocol)– a new grammar with Antlr v4– the support of JDK 8 and lambdas
99
Questions & Answers
Thank you! @glaforge
http://glaforge.appspot.com
http://gplus.to/glaforge
Image credits• lift-off: http://www.wpclipart.com/space/ships/space_shuttle/Space_Shuttle_liftoff.png
• anniversary: http://www.empowernetwork.com/fam/files/2013/03/happy_birthday_cake_with_candles-1920x1200.jpg
• cerisier: http://wallpaperswide.com/cherry_blossom_3-wallpapers.html
• NKOTB: http://images1.fanpop.com/images/photos/2300000/nkotb-new-kids-on-the-block-2314664-1280-960.jpg
• lunar module: http://www.clavius.org/img/lm-diag.gif
• tomates: http://www.infoescola.com/wp-content/uploads/2011/01/tomate.jpg
• patates: http://toooof.free.fr/blogs/captainslip/screenshots/pommes_de_terre.jpg
• coins: http://www.coins-jewelry.com/c22.png
• more coins: http://diamond-center.co.il/upload/articles/gold-coins1.jpg
• binary: http://okletsgo.co.uk/img/binary.jpg
• grumpy: https://si0.twimg.com/profile_images/3115998027/b47c180a703a5ffa7d1437a66f545dc0.jpeg
• singe: http://static.ddmcdn.com/gif/how-to-draw-animals-31.jpg
• warning: http://th07.deviantart.net/fs71/PRE/i/2012/261/8/6/warning_gangnam_style_zone_by_untoucheddesigns-d5f6bal.png
• coyote: http://nittygriddy.com/wp-content/uploads/2011/01/Wiley-Coyote-Help.jpg
• ring: http://img.banggood.com/images/upload/2012/limin/SKU028431_11.JPG
• magnifying glass: http://www.renders-graphiques.fr/image/upload/normal/loupe.png
• work in progress: http://www.sbscompany.org/multimedia/immagini/work-in-progress.png
• tab key: http://www.meganga.com/wp-content/uploads/2012/03/Tab-Key-Word-Tutorials.jpg
• chronomètre: http://www.moineau-instruments.com/59-thickbox/chronometre-mecanique-1-10-t15-mn-2-fonctions.jpg
• that’s all folks: http://4.bp.blogspot.com/-wJxosualm48/T4M_spcUUjI/AAAAAAAAB8E/njfLjNZQdsc/s1600/thats-all-folks.jpg
• MOP: http://imagethumbnails.milo.com/024/913/894/trimmed/24913521_25989894_trimmed.jpg
• grammar: http://edudemic.com/wp-content/uploads/2012/11/connected-learner-grammar.jpg
102