Lift off with Groovy 2 at JavaOne 2013

  • 1,562 views
Uploaded on

Presentations on the features of the Groovy 2.x line

Presentations on the features of the Groovy 2.x line

More in: Technology , Business
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
1,562
On Slideshare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
32
Comments
0
Likes
2

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. © 2013 Guillaume Laforge. All rights reserved. Do not distribute without permission. GuillaumeLaforge @glaforge  Lift-offwithGroovy2 ...andbeyond!
  • 2. © 2013 Guillaume Laforge. All rights reserved. Do not distribute without permission. GuillaumeLaforge @glaforge  Lift-offwithGroovy2 ...andbeyond!
  • 3. GuillaumeLaforge @glaforge  http://glaforge.appspot.com  http://gplus.to/glaforge 
  • 4. GuillaumeLaforge @glaforge  http://glaforge.appspot.com  http://gplus.to/glaforge  Presentation will be uploaded to https://speakerdeck.com/glaforge
  • 5. A dynamic language, optionally typed Groovy
  • 6. ...statically type checked and compiled as needed Groovy
  • 7. Syntax deriving from Java, thus easy to learn Groovy
  • 8. million downloads in 2012 1.7
  • 9. 10
  • 10. Ablossoming Ecosystem
  • 11. GVM
  • 12. Let’s start the engine Modularity Java 7: ProjectCoin & invokedynamic Static typechecking & compilation
  • 13. Modularity « Not everybody needs everything, all the time, at the same time! »
  • 14. 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
  • 15. 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
  • 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
  • 17. « Let’s go shopping »
  • 18. 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
  • 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
  • 20. Extension modules • Create your own extension module – contribute static methods 20 package  foo class  StaticStringExtension  {        static  hi(String  self)  {                "Hi!"        } } //  usage:  String.hi()
  • 21. 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 21
  • 22. Java 7 theme « ProjectCoin » syntax InvokeDynamic support
  • 23. 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 23
  • 24. 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 25
  • 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
  • 26. Woot!
  • 27. 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
  • 28. A « static » theme Static type checking Static compilation
  • 29. Static type checking • Goal: make the compiler grumpy! – throw errors at compile-time •rather than at runtime 30
  • 30. We don’t need dynamic features all the time!
  • 31. We don’t need dynamic features all the time! Nah !
  • 32. 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 32
  • 33. Static type checking • The compiler should infer types... – less explicit types and casts – fine grained type inference •« flow typing » •« lowest upper bound » 33
  • 34. Static type checking • But the compiler should understand extension methods – allows a good level of dynamism, despite the additional restrictions 34
  • 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 } 35
  • 36. 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
  • 37. 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
  • 38. 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
  • 39. 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' 36
  • 40. 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 36
  • 41. 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 36
  • 42. 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 36
  • 43. 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 } 37
  • 44. 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 37
  • 45. 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() 37
  • 46. 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
  • 47. 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
  • 48. 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
  • 49. 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
  • 50. 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
  • 51. 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() } 39
  • 52. 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 39
  • 53. 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 39
  • 54. Instanceof checks @TypeChecked   void  test(Object  val)  {        if  (val  instanceof  String)  {                println  val.toUpperCase()        }  else  if  (val  instanceof  Number)  {                println  "X"  *  val.intValue()        } } 40
  • 55. 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
  • 56. 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
  • 57. 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
  • 58. 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
  • 59. 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
  • 60. 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
  • 61. Not really clean, your code!
  • 62. Not really clean, your code! Grmmpf...no!
  • 63. 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
  • 64. But if it ain’t dynamic, can we compile it statically?
  • 65. But if it ain’t dynamic, can we compile it statically? But of course!!!
  • 66. 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 46
  • 67. 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
  • 68. I canz do what I want wiz your code
  • 69. I canz do what I want wiz your code Niark !
  • 70. 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
  • 71. 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() } 50
  • 72. 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 50
  • 73. 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 50
  • 74. 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 50
  • 75. 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! 50
  • 76. 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
  • 77. 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.71.82.x 52
  • 78. ...and now, onto Groovy2.1 Complete Invoke Dynamic support Meta-annotations Advanced compilerconfiguration Typecheckerextensions
  • 79. Invoke Dynamic Complete support of Invoke Dynamic
  • 80. Meta-annotations One annotation to rule them all!
  • 81. Meta-annotations • Create meta-annotations which combine and/or parameterize other annotations • And which work with AST transformations 56
  • 82. Meta-annotations @Immutable @ToString(excludes  =  ["age"]) @AnnotationCollector @interface  MyAlias  {} 57
  • 83. Meta-annotations @Immutable @ToString(excludes  =  ["age"]) @AnnotationCollector @interface  MyAlias  {} Collected annotations 57
  • 84. Meta-annotations @Immutable @ToString(excludes  =  ["age"]) @AnnotationCollector @interface  MyAlias  {} Collected annotations The collector 57
  • 85. Meta-annotations @Immutable @ToString(excludes  =  ["age"]) @AnnotationCollector @interface  MyAlias  {} Collected annotations The collector Your own annotation alias 57
  • 86. Meta-annotations @Immutable @ToString(excludes  =  ["age"]) @AnnotationCollector @interface  MyAlias  {} @MyAlias class  Person  {        String  name        int  age } Collected annotations The collector Your own annotation alias 57
  • 87. 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 57
  • 88. @DelegatesTo annotation Richer tooling support for Domain-Specific Languages
  • 89. @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
  • 90. @DelegatesTo annotation exec(spec)  {        foo() } 60
  • 91. @DelegatesTo annotation class  ExecSpec  {        void  foo() } exec(spec)  {        foo() } 60
  • 92. @DelegatesTo annotation class  ExecSpec  {        void  foo() } void  exec(ExecSpec  sp,  Closure  c)  {        c.delegate  =  sp        c() } exec(spec)  {        foo() } 60
  • 93. @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() 60
  • 94. @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() 60
  • 95. @DelegatesTo annotation • With another delegation strategy void  exec(ExecSpec  sp,  Closure  c)  {        c.delegate  =  sp        c.resolveStrategy  =  DELEGATE_FIRST        c() } 61
  • 96. @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
  • 97. @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
  • 98. Extend the static type checker To go even further than Java itself!
  • 99. 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
  • 100. 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
  • 101. 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
  • 102. 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
  • 103. Extend the static type checker onMethodSelection  {  expr,  method  -­‐>  ...  } afterMethodCall  {  mc  -­‐>  ...  } unresolvedVariable  {  var  -­‐>  ...  } methodNotFound  {  receiver,  name,  argList,  argTypes,  call  -­‐>  ...  } incompatibleAssignment  {  lhsType,  rhsType,  expr  -­‐>  ...  } 67
  • 104. 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
  • 105. 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
  • 106. 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
  • 107. 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
  • 108. Compiler configuration Custom base script class Configuration script Configuration DSL
  • 109. 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
  • 110. 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
  • 111. Compiler customization • Add the @ToString AST transformation import  groovy.transform.ToString import  org.codehaus.groovy.control.customizers              .ASTTransformationCustomizer configuration.addCompilationCustomizer(        new  ASTTransformationCustomizer(ToString) ) 72
  • 112. 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 72
  • 113. Compiler customization • A small DSL to configure the customization configuration.customizers  {        //  apply  to  MyBean.groovy        source(basename:  'MyBean')  {                ast(ToString)        } } 73
  • 114. 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
  • 115. 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
  • 116. To learn more... Groovy2.0 http://groovy.codehaus.org/Groovy+2.0+release+notes Groovy2.1 http://groovy.codehaus.org/Groovy+2.1+release+notes
  • 117. And what’s next? Groovy2.2,2.3&3 ! New « MOP » NewGrammar with Antlr v4 Java8Lambdassupport
  • 118. A few words about the roadmap 2014201420132012 Groovy 2.1 Groovy 2.0Groovy 2.0 Groovy 2.2 Groovy 2.3 76 Groovy 3.0
  • 119. A few words about the roadmap 2014201420132012 Groovy 2.1 Groovy 2.0Groovy 2.0 Groovy 2.2 Groovy 2.3 76 Groovy 3.0
  • 120. A few words about the roadmap 2014201420132012 Groovy 2.1 Groovy 2.0Groovy 2.0 Groovy 2.2 Groovy 2.3 76 Groovy 3.0
  • 121. Groovy 2.2 Implicitclosurecoercion @Memoized transformation DelegatingScript base script class
  • 122. Implicit closure coercion 78
  • 123. Implicit closure coercion interface  Predicate<T>  {        boolean  test(T  t) } List<T>  filter(Predicate<T>  p) 78
  • 124. 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
  • 125. 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
  • 126. 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
  • 127. 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
  • 128. 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
  • 129. 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
  • 130. 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
  • 131. DelegatingScript base script class • Special base script class to delegate method calls and property accesses to a delegatee 79
  • 132. DelegatingScript base script class • Special base script class to delegate method calls and property accesses to a delegatee Handy for DSLs! 79
  • 133. 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
  • 134. 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
  • 135. 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
  • 136. 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
  • 137. 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
  • 138. 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
  • 139. 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
  • 140. 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
  • 141. 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
  • 142. 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
  • 143. groovysh doc command 81
  • 144. groovysh doc command Launches your browser with the JavaDoc and GDK doc of the class 81
  • 145. groovysh code completion 82
  • 146. groovysh code completion Import completion 82
  • 147. groovysh code completion Import completion Method call completion 82
  • 148. @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) 83
  • 149. 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
  • 150. 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
  • 151. Likely in Groovy 2.3 Traits GroovyDoc rewrite New documentation & website
  • 152. Trait implementation 87
  • 153. Trait implementation trait  FlyingAbility  {        String  fly()  {                "I  believe  I  can  fly!"        } } 87
  • 154. Trait implementation trait  FlyingAbility  {        String  fly()  {                "I  believe  I  can  fly!"        } } A trait keyword applying the @Trait transformation 87
  • 155. Trait implementation trait  FlyingAbility  {        String  fly()  {                "I  believe  I  can  fly!"        } } A trait keyword applying the @Trait transformation class  Car  implements  FlyingAbility  {} 87
  • 156. 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
  • 157. 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
  • 158. GroovyDoc rewrite 88
  • 159. GroovyDoc rewrite GroovyDoc != Sexy Doc 88
  • 160. New documentation and website • New reference documentation and guides using AsciiDoctor • New website with a refreshed skin and the new content 89
  • 161. Groovy 3 New MOP New Antlr v4 grammar JDK 8 lambda support
  • 162. MOP 2
  • 163. Antlr4 grammar
  • 164. λ JDK 8
  • 165. 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
  • 166. Summary •Groovy 2.1 – Invoke Dynamic support completed – @DelegatesTo annotation – type checker extensions for DSLs – meta-annotations 96
  • 167. Summary • Groovy 2.2 – implicit closure coercion – @Memoized transformation – DelegatingScript for script DSLs – groovysh improvements 97
  • 168. Summary • Groovy 2.3 – traits – new GroovyDoc – new documentation – new website 98
  • 169. Summary • Groovy 3 – a new MOP (Meta-Object Protocol) – a new grammar with Antlr v4 – the support of JDK 8 and lambdas 99
  • 170. Questions&Answers
  • 171. Thankyou! @glaforge  http://glaforge.appspot.com  http://gplus.to/glaforge 
  • 172. 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