Lift-off with Groovy 2

Lift-off with Groovy 2

Overview of the past, present, and upcoming features of the Groovy 2 line.

137d3908243acfc30e126615d59d4e6d?s=128

Guillaume Laforge

September 10, 2013
Tweet

Transcript

  1. © 2013 SpringOne 2GX. All rights reserved. Do not distribute

    without permission. Guillaume Laforge @glaforge  Lift-off with Groovy 2 ...and beyond!
  2. © 2013 SpringOne 2GX. All rights reserved. Do not distribute

    without permission. Guillaume Laforge @glaforge  Lift-off with Groovy 2 ...and beyond!
  3. Guillaume Laforge @glaforge  http://glaforge.appspot.com  http://gplus.to/glaforge 

  4. Guillaume Laforge @glaforge  http://glaforge.appspot.com  http://gplus.to/glaforge  Presentation will

    be uploaded to https://speakerdeck.com/glaforge
  5. S P R I N G I O C O

    R E : Groovy
  6. A dynamic language, optionally typed Groovy

  7. ...statically type checked and compiled as needed Groovy

  8. Syntax deriving from Java, thus easy to learn Groovy

  9. 1.7 million downloads in 2012

  10. None
  11. 10

  12. A blossoming Ecosystem

  13. None
  14. None
  15. None
  16. None
  17. GVM

  18. None
  19. GVM

  20. GVM GROOVY ENVIRONMENT MANAGER

  21. GVM: Groovy enVironment Manager • The new kid on the

    block – http://gvmtool.net/ — @gvmtool • Manage parallel versions of the various ecosystem projects • Supports... – Groovy, Grails, Griffon, Gradle, Vert.x • On Linux, MacOS, Cygwin, Solaris, FreeBSD 16
  22. Ratpack • Lightweight Netty-based web app toolkit @GrabResolver("https://oss.jfrog.org/artifactory/repo") @Grab("org.ratpack-framework:ratpack-groovy:0.9.0-SNAPSHOT") import

    static org.ratpackframework.groovy.RatpackScript.ratpack import org.ratpackframework.groovy.templating.TemplateRenderer ratpack { handlers { get { response.send "This is the app root" } get("date") { get(TemplateRenderer).render "date.html" } assets "public" } } 17
  23. Let’s start the engine with Groovy 2.0 Modularity Java 7:

    Project Coin & invoke dynamic Static type checking & compilation
  24. Modularity « Not everybody needs everything, all the time, at

    the same time! »
  25. 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 » 20
  26. 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 21
  27. 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 21
  28. « Let’s go shopping »

  29. 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") 23
  30. 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 23
  31. Extension modules • Create your own extension module – contribute

    static methods 24 package  foo class  StaticStringExtension  {        static  hi(String  self)  {                "Hi!"        } } //  usage:  String.hi()
  32. Extension module descriptor • META-INF/ – services/ • org.codehaus.groovy.runtime.ExtensionModule moduleName

     =  stringExtensions moduleVersion  =  1.0 //  comma  separated  list  of  FQN  class  names extensionClasses  =  foo.StringExtension //  comma  separated  list  of  FQN  class  names staticExtensionClasses  =  foo.StaticStringExtension 25
  33. Java 7 theme « Project Coin » syntax Invoke Dynamic

    support
  34. Binary literals • In addition to decimal, octal and hexa

    • A new binary representation: int  x  =  0b10101111 assert  x  ==  175   byte  aByte  =  0b00100001 assert  aByte  ==  33   int  anInt  =  0b1010000101000101 assert  anInt  ==  41285 27
  35. None
  36. Underscores in literals • Use underscores in number literals long

     creditCardNumber  =  1234_5678_9012_3456L long  socialSecurityNumbers  =  999_99_9999L float  monetaryAmount  =  12_345_132.12 long  hexBytes  =  0xFF_EC_DE_5E long  hexWords  =  0xFFEC_DE5E long  maxLong  =  0x7fff_ffff_ffff_ffffL long  alsoMaxLong  =  9_223_372_036_854_775_807L long  bytes  =  0b11010010_01101001_10010100_10010010 29
  37. 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  */ } 30
  38. Woot!

  39. 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 32
  40. A « static » theme Static type checking Static compilation

  41. Static type checking • Goal: make the compiler grumpy! –

    throw errors at compile-time • rather than at runtime 34
  42. We don’t need dynamic features all the time!

  43. We don’t need dynamic features all the time! Nah !

  44. Static type checking • A « grumpy » compiler should...

    – say when there’s a typo in a method or variable name – complain when a non-existent method is called – or on bad assignments or use a bad return type 36
  45. Static type checking • The compiler should infer types... –

    less explicit types and casts – fine grained type inference •« flow typing » •« lowest upper bound » 37
  46. Static type checking • But the compiler should understand extension

    methods – allows a good level of dynamism, despite the additional restrictions 38
  47. Typos import  groovy.transform.TypeChecked   void  method()  {}   @TypeChecked  test()

     {        //  Cannot  find  matching  method  metthhoood()        metthhoood()          def  name  =  "Guillaume"        //  variable  naamme  is  undeclared        println  naamme } 39
  48. 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 39
  49. 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 39
  50. 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 39
  51. 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  =  0 i  +=  '1' 40
  52. 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  =  0 i  +=  '1' Compilation error 40
  53. 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  =  0 i  +=  '1' Compilation error Compilation error 40
  54. 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  =  0 i  +=  '1' Compilation error Compilation error Compilation error 40
  55. Wrong return type //  checks  if/else  branch  return  values @TypeChecked

    int  method()  {        if  (true)  {  'String'  }        else  {  42  } } //  works  for  switch/case  &  try/catch/finally   //  transparent  toString()  implied @TypeChecked String  greeting(String  name)  {        def  sb  =  new  StringBuilder()        sb  <<  "Hi  "  <<  name } 41
  56. Wrong return type //  checks  if/else  branch  return  values @TypeChecked

    int  method()  {        if  (true)  {  'String'  }        else  {  42  } } //  works  for  switch/case  &  try/catch/finally   //  transparent  toString()  implied @TypeChecked String  greeting(String  name)  {        def  sb  =  new  StringBuilder()        sb  <<  "Hi  "  <<  name } Compilation error 41
  57. Wrong return type //  checks  if/else  branch  return  values @TypeChecked

    int  method()  {        if  (true)  {  'String'  }        else  {  42  } } //  works  for  switch/case  &  try/catch/finally   //  transparent  toString()  implied @TypeChecked String  greeting(String  name)  {        def  sb  =  new  StringBuilder()        sb  <<  "Hi  "  <<  name } Compilation error In the end, call StringBuilder’s toString() 41
  58. 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        } } 42
  59. 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 42
  60. 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 42
  61. 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 42
  62. 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 42
  63. Mix dynamic & statically checked code @TypeChecked String  greeting(String  name)

     {        //  call  method  with  dynamic  behavior        //  but  with  proper  signature        generateMarkup(name.toUpperCase()) }   //  usual  dynamic  behavior String  generateMarkup(String  name)  {        def  sw  =  new  StringWriter()        new  MarkupBuilder(sw).html  {                body  {                        div  name                }        }        sw.toString() } 43
  64. Mix dynamic & statically checked code @TypeChecked String  greeting(String  name)

     {        //  call  method  with  dynamic  behavior        //  but  with  proper  signature        generateMarkup(name.toUpperCase()) }   //  usual  dynamic  behavior String  generateMarkup(String  name)  {        def  sw  =  new  StringWriter()        new  MarkupBuilder(sw).html  {                body  {                        div  name                }        }        sw.toString() } Statically checked 43
  65. Mix dynamic & statically checked code @TypeChecked String  greeting(String  name)

     {        //  call  method  with  dynamic  behavior        //  but  with  proper  signature        generateMarkup(name.toUpperCase()) }   //  usual  dynamic  behavior String  generateMarkup(String  name)  {        def  sw  =  new  StringWriter()        new  MarkupBuilder(sw).html  {                body  {                        div  name                }        }        sw.toString() } Statically checked Dynamic 43
  66. Instanceof checks @TypeChecked   void  test(Object  val)  {    

       if  (val  instanceof  String)  {                println  val.toUpperCase()        }  else  if  (val  instanceof  Number)  {                println  "X"  *  val.intValue()        } } 44
  67. 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 44
  68. 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 44
  69. 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 Understand GDK’s method: String#multiply(int) 44
  70. Lowest Upper Bound • The smallest common « super »

    type – might be virtual (« non-denotable ») @TypeChecked  test()  {        //  an  integer  and  a  BigDecimal        return  [1234,  3.14] } 45
  71. 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<Number & Comparable & Serializable> 45
  72. 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  ! } 46
  73. Not really clean, your code!

  74. Not really clean, your code! Grmmpf...no!

  75. 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 is OK – if enough type information is available 48
  76. No dynamic metaprogramming @TypeChecked   void  test()  {    

       Integer.metaClass.foo  =  {}        123.foo() } 49
  77. No dynamic metaprogramming @TypeChecked   void  test()  {    

       Integer.metaClass.foo  =  {}        123.foo() } metaClass dynamic property access not allowed 49
  78. No dynamic metaprogramming @TypeChecked   void  test()  {    

       Integer.metaClass.foo  =  {}        123.foo() } metaClass dynamic property access not allowed Unknown method 49
  79. Explicit type for closure parameters @TypeChecked  test()  {    

       ["a",  "b",  "c"].collect  {                it.toUpperCase()  //  Not  OK!        } } 50
  80. Explicit type for closure parameters @TypeChecked  test()  {    

       ["a",  "b",  "c"].collect  {  String  it  -­‐>                it.toUpperCase()  //  OK,  a  String        } } 50
  81. Explicit type for closure parameters @TypeChecked  test()  {    

       ["a",  "b",  "c"].collect  {  String  it  -­‐>                it.toUpperCase()  //  OK,  a  String        } } Must specify the type explicitely 50
  82. Explicit type for closure parameters @TypeChecked  test()  {    

       ["a",  "b",  "c"].collect  {  String  it  -­‐>                it.toUpperCase()  //  OK,  a  String        } } Must specify the type explicitely The list could contain anything! 50
  83. Explicit type for closure parameters @TypeChecked  test(List  myListParameter)  {  

         myListParameter.collect  {  String  it  -­‐>                it.toUpperCase()        } } Must specify the type explicitely The list could contain anything! 50
  84. But if it ain’t dynamic, can we compile it statically?

  85. But if it ain’t dynamic, can we compile it statically?

    But of course! !
  86. 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 < 7 to gain performance improvements 52
  87. 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 53
  88. I canz do what I want wiz your code

  89. I canz do what I want wiz your code Niark

    !
  90. 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 55
  91. Mix statically compiled code with dynamic @CompileStatic String  greeting(String  name)

     {        //  call  method  with  dynamic  behavior        //  but  with  proper  signature        generateMarkup(name.toUpperCase()) }   //  usual  dynamic  behavior String  generateMarkup(String  name)  {        def  sw  =  new  StringWriter()        new  MarkupBuilder(sw).html  {                body  {                        div  name                }        }        sw.toString() } 56
  92. Mix statically compiled code with dynamic @CompileStatic String  greeting(String  name)

     {        //  call  method  with  dynamic  behavior        //  but  with  proper  signature        generateMarkup(name.toUpperCase()) }   //  usual  dynamic  behavior String  generateMarkup(String  name)  {        def  sw  =  new  StringWriter()        new  MarkupBuilder(sw).html  {                body  {                        div  name                }        }        sw.toString() } Statically compiled 56
  93. Mix statically compiled code with dynamic @CompileStatic String  greeting(String  name)

     {        //  call  method  with  dynamic  behavior        //  but  with  proper  signature        generateMarkup(name.toUpperCase()) }   //  usual  dynamic  behavior String  generateMarkup(String  name)  {        def  sw  =  new  StringWriter()        new  MarkupBuilder(sw).html  {                body  {                        div  name                }        }        sw.toString() } Statically compiled Dynamic 56
  94. Mix statically compiled code with dynamic @CompileStatic String  greeting(String  name)

     {        //  call  method  with  dynamic  behavior        //  but  with  proper  signature        generateMarkup(name.toUpperCase()) }   //  usual  dynamic  behavior String  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 56
  95. Mix statically compiled code with dynamic @CompileStatic String  greeting(String  name)

     {        //  call  method  with  dynamic  behavior        //  but  with  proper  signature        generateMarkup(name.toUpperCase()) }   //  usual  dynamic  behavior String  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! 56
  96. What about performance? • Comparisons between: – Java – Groovy

    •with static compilation — Groovy 2.0 •with primitive type optimizations — Groovy 1.8+ •no optimization — Groovy 1.7 57
  97. What about performance? Fibonacci Pi (π) quadrature Binary trees Java

    Static compilation 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 s 1.7 1.8 2.x 58
  98. ...and now, onto Groovy 2.1 Complete Invoke Dynamic support Meta-annotations

    Advanced compiler configuration Type checker extensions
  99. Invoke Dynamic Complete support of Invoke Dynamic

  100. Complete « Invoke Dynamic » support • In Groovy 2.0,

    all method call weren’t going through the « indy » support – only normal method calls – still joint usage of the « call site caching » technique •On JDK 7, with the « indy » JAR, Groovy 2.1 uses « invoke dynamic » everywhere • On JDK < 7, still using « call site caching » • Problem: invalid OSGi bundle, fixed in 2.2 61
  101. Meta-annotations One annotation to rule them all!

  102. Meta-annotations • Create meta-annotations which combine and/or parameterize other annotations

    • And which work with AST transformations 63
  103. Meta-annotations @Immutable @ToString(excludes  =  ["age"]) @AnnotationCollector @interface  MyAlias  {} 64

  104. Meta-annotations @Immutable @ToString(excludes  =  ["age"]) @AnnotationCollector @interface  MyAlias  {} Collected

    annotations 64
  105. Meta-annotations @Immutable @ToString(excludes  =  ["age"]) @AnnotationCollector @interface  MyAlias  {} Collected

    annotations The collector 64
  106. Meta-annotations @Immutable @ToString(excludes  =  ["age"]) @AnnotationCollector @interface  MyAlias  {} Collected

    annotations The collector Your own annotation alias 64
  107. Meta-annotations @Immutable @ToString(excludes  =  ["age"]) @AnnotationCollector @interface  MyAlias  {} @MyAlias

    class  Person  {        String  name        int  age } Collected annotations The collector Your own annotation alias 64
  108. Meta-annotations @Immutable @ToString(excludes  =  ["age"]) @AnnotationCollector @interface  MyAlias  {} @MyAlias

    class  Person  {        String  name        int  age } Collected annotations The collector Your own annotation alias Use your meta- annotation 64
  109. @DelegatesTo annotation Richer tooling support for Domain-Specific Languages

  110. @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' } 66
  111. @DelegatesTo annotation exec(spec)  {        foo() } 67

  112. @DelegatesTo annotation class  ExecSpec  {        void  foo()

    } exec(spec)  {        foo() } 67
  113. @DelegatesTo annotation class  ExecSpec  {        void  foo()

    } void  exec(ExecSpec  sp,  Closure  c)  {        c.delegate  =  sp        c() } exec(spec)  {        foo() } 67
  114. @DelegatesTo annotation class  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() 67
  115. @DelegatesTo annotation class  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() 67
  116. @DelegatesTo annotation • With another delegation strategy void  exec(ExecSpec  sp,

     Closure  c)  {        c.delegate  =  sp        c.resolveStrategy  =  DELEGATE_FIRST        c() } 68
  117. @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) 68
  118. @DelegatesTo annotation • Use Target to specify a particular delegatee

    void  exec(ExecSpec  sp,  Closure  c)  {        c.delegate  =  sp        c() } 69
  119. @DelegatesTo annotation • Use Target to specify a particular delegatee

    void  exec(ExecSpec  sp,  Closure  c)  {        c.delegate  =  sp        c() } @DelegatesTo.Target(‘‘id’’) 69
  120. @DelegatesTo annotation • Use Target to specify a particular delegatee

    void  exec(ExecSpec  sp,  Closure  c)  {        c.delegate  =  sp        c() } @DelegatesTo.Target(‘‘id’’) @DelegatesTo(target = ‘‘id’’) 69
  121. @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 70
  122. Extend the static type checker To go even further than

    Java itself!
  123. 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... } 72
  124. 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 72
  125. 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 – ... 73
  126. Extend the static type checker • Your extension has access

    to an event-oriented API 74 • onMethodSelection • afterMethodCall • beforeMethodCall • afterVisitMethod • beforeVisitMethod • methodNotFound • unresolvedVariable • unresolvedProperty • unresolvedAttribute • incompatibleAssignment
  127. Extend the static type checker onMethodSelection  {  expr,  method  -­‐>

     ...  } afterMethodCall  {  mc  -­‐>  ...  } unresolvedVariable  {  var  -­‐>  ...  } methodNotFound  {  receiver,  name,  argList,  argTypes,  call  -­‐>  ...  } incompatibleAssignment  {  lhsType,  rhsType,  expr  -­‐>  ...  } 75
  128. Extend the static type checker onMethodSelection  {  expr,  method  -­‐>

     ...  } afterMethodCall  {  mc  -­‐>  ...  } unresolvedVariable  {  var  -­‐>  ...  } methodNotFound  {  receiver,  name,  argList,  argTypes,  call  -­‐>  ...  } incompatibleAssignment  {  lhsType,  rhsType,  expr  -­‐>  ...  } MyExtension.groovy 75
  129. 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! 75
  130. 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 75
  131. 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 76
  132. Compiler configuration Custom base script class Configuration script Configuration DSL

  133. 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 78
  134. Compiler customization • New options – --basescript to define a

    base script class for your scripts – --configscript to indicate a script to configure the CompilerConfiguration object 79
  135. Compiler customization • Add the @ToString AST transformation import  groovy.transform.ToString

    import  org.codehaus.groovy.control.customizers              .ASTTransformationCustomizer configuration.addCompilationCustomizer(        new  ASTTransformationCustomizer(ToString) ) 80
  136. Compiler customization • Add the @ToString AST transformation import  groovy.transform.ToString

    import  org.codehaus.groovy.control.customizers              .ASTTransformationCustomizer configuration.addCompilationCustomizer(        new  ASTTransformationCustomizer(ToString) ) CompilerConfiguration instance, injected by default 80
  137. Compiler customization • A small DSL to configure the customization

    configuration.customizers  {        //  apply  to  MyBean.groovy        source(basename:  'MyBean')  {                ast(ToString)        } } 81
  138. 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)        } } 81
  139. 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'                }        } } 81
  140. To learn more... Groovy 2.0 http://groovy.codehaus.org/Groovy+2.0+release+notes Groovy 2.1 http://groovy.codehaus.org/Groovy+2.1+release+notes

  141. And what’s next? Groovy 2.2, 2.3 & 3 ! New

    « MOP » New Grammar with Antlr v4 Java 8 Lambdas support
  142. A few words about the roadmap 2014 2014 2013 2012

    Groovy 2.1 Groovy 2.0 Groovy 2.0 Groovy 2.2 Groovy 2.3 84 Groovy 3.0
  143. A few words about the roadmap 2014 2014 2013 2012

    Groovy 2.1 Groovy 2.0 Groovy 2.0 Groovy 2.2 Groovy 2.3 84 Groovy 3.0
  144. A few words about the roadmap 2014 2014 2013 2012

    Groovy 2.1 Groovy 2.0 Groovy 2.0 Groovy 2.2 Groovy 2.3 84 Groovy 3.0
  145. Groovy 2.2 Implicit closure coercion @Memoized transformation DelegatingScript base script

    class
  146. Implicit closure coercion 86

  147. Implicit closure coercion interface  Predicate<T>  {        boolean

     test(T  t) } List<T>  filter(Predicate<T>  p) 86
  148. 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... 86
  149. 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... 86
  150. 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! 86
  151. 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! 86
  152. 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! 86
  153. 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! 86
  154. 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! And go beyond Java, by making it work on abstract classes as well 86
  155. DelegatingScript base script class • Special base script class to

    delegate method calls and property accesses to a delegatee 87
  156. DelegatingScript base script class • Special base script class to

    delegate method calls and property accesses to a delegatee Handy for DSLs! 87
  157. DelegatingScript base script class • Special base script class to

    delegate method calls and property accesses to a delegatee Handy for DSLs! name  =  "Guillaume" sayHi() 87
  158. 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() 87
  159. 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 87
  160. 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() 87
  161. 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" 88
  162. 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 88
  163. 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 88
  164. 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 88
  165. 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 88
  166. 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! 88
  167. groovysh doc command 89

  168. groovysh doc command Launches your browser with the JavaDoc and

    GDK doc of the class 89
  169. groovysh code completion 90

  170. groovysh code completion Import completion 90

  171. groovysh code completion Import completion Method call completion 90

  172. @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  return expensiveOp(1,  2)   //  immediate  result  returned expensiveOp(1,  2) 91
  173. @DelegatesTo with generic type tokens @groovy.transform.InheritConstructors class  MyList  extends  LinkedList<String>

     {} public  <T>  Object  map(            @DelegatesTo.Target  List<T>  target,              @DelegatesTo(genericTypeIndex  =  0)  Closure  arg)  {        arg.delegate  =  target.join('')        arg() } def  test()  {        map(new  MyList(['f',  'o',  'o']))  {                assert  toUpperCase()  ==  'FOO'        } } 92
  174. @DelegatesTo with generic type tokens @groovy.transform.InheritConstructors class  MyList  extends  LinkedList<String>

     {} public  <T>  Object  map(            @DelegatesTo.Target  List<T>  target,              @DelegatesTo(genericTypeIndex  =  0)  Closure  arg)  {        arg.delegate  =  target.join('')        arg() } def  test()  {        map(new  MyList(['f',  'o',  'o']))  {                assert  toUpperCase()  ==  'FOO'        } } We want to delegate to the token type T 92
  175. @DelegatesTo with generic type tokens @groovy.transform.InheritConstructors class  MyList  extends  LinkedList<String>

     {} public  <T>  Object  map(            @DelegatesTo.Target  List<T>  target,              @DelegatesTo(genericTypeIndex  =  0)  Closure  arg)  {        arg.delegate  =  target.join('')        arg() } def  test()  {        map(new  MyList(['f',  'o',  'o']))  {                assert  toUpperCase()  ==  'FOO'        } } We want to delegate to the token type T We define the index of the type token 92
  176. @DelegatesTo with generic type tokens @groovy.transform.InheritConstructors class  MyList  extends  LinkedList<String>

     {} public  <T>  Object  map(            @DelegatesTo.Target  List<T>  target,              @DelegatesTo(genericTypeIndex  =  0)  Closure  arg)  {        arg.delegate  =  target.join('')        arg() } def  test()  {        map(new  MyList(['f',  'o',  'o']))  {                assert  toUpperCase()  ==  'FOO'        } } We want to delegate to the token type T We define the index of the type token This is String’s toUpperCase() method 92
  177. 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') 93
  178. 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] 94
  179. Likely in Groovy 2.3 Traits GroovyDoc rewrite New documentation &

    website
  180. Trait implementation 96

  181. Trait implementation trait  FlyingAbility  {        String  fly()

     {                "I  believe  I  can  fly!"        } } 96
  182. Trait implementation trait  FlyingAbility  {        String  fly()

     {                "I  believe  I  can  fly!"        } } A trait keyword applying the @Trait transformation 96
  183. Trait implementation trait  FlyingAbility  {        String  fly()

     {                "I  believe  I  can  fly!"        } } A trait keyword applying the @Trait transformation class  Car  implements  FlyingAbility  {} 96
  184. 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 96
  185. 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!" 96
  186. GroovyDoc rewrite 97

  187. GroovyDoc rewrite GroovyDoc != Sexy Doc 97

  188. New documentation and website • New reference documentation and guides

    using AsciiDoctor • New website with a refreshed skin and the new content 98
  189. Groovy 3 New MOP New Antlr v4 grammar JDK 8

    lambda support
  190. MOP 2

  191. Antlr 4 grammar

  192. λ JDK 8

  193. None
  194. 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 104
  195. Summary •Groovy 2.1 – Invoke Dynamic support completed – @DelegatesTo

    annotation – type checker extensions for DSLs – meta-annotations 105
  196. Summary • Groovy 2.2 – implicit closure coercion – @Memoized

    transformation – DelegatingScript for script DSLs – groovysh improvements 106
  197. Summary • Groovy 2.3 – traits – new GroovyDoc –

    new documentation – new website 107
  198. Summary • Groovy 3 – a new MOP (Meta-Object Protocol)

    – a new grammar with Antlr v4 – the support of JDK 8 and lambdas 108
  199. Questions & Answers

  200. Thank you! @glaforge  http://glaforge.appspot.com  http://gplus.to/glaforge 

  201. 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 111