Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Groovy in 2014 and beyond

Groovy in 2014 and beyond

Talk given at the Greach conference in Madrid, in 2014.
Covers features of Groovy 2.2 and 2.3, and talks about Groovy 3's roadmap.

Guillaume Laforge

March 28, 2014
Tweet

More Decks by Guillaume Laforge

Other Decks in Technology

Transcript

  1. @glaforge — Greach 2014 Implicit closure coercion !6 interface  Predicate

     {          boolean  test(something)   }   ! List  filter(List  l,  Predicate  p)  {          l.findAll  {  p.test(it)  }   }   ! filter([1,  2,  3,  4],  {  it  >  2  }  as  Predicate)   ! filter([1,  2,  3,  4],  {  it  >  2  })   ! filter([1,  2,  3,  4])  {  it  >  2  }
  2. @glaforge — Greach 2014 Implicit closure coercion !6 interface  Predicate

     {          boolean  test(something)   }   ! List  filter(List  l,  Predicate  p)  {          l.findAll  {  p.test(it)  }   }   ! filter([1,  2,  3,  4],  {  it  >  2  }  as  Predicate)   ! filter([1,  2,  3,  4],  {  it  >  2  })   ! filter([1,  2,  3,  4])  {  it  >  2  } « Functional » interface
  3. @glaforge — Greach 2014 Implicit closure coercion !6 interface  Predicate

     {          boolean  test(something)   }   ! List  filter(List  l,  Predicate  p)  {          l.findAll  {  p.test(it)  }   }   ! filter([1,  2,  3,  4],  {  it  >  2  }  as  Predicate)   ! filter([1,  2,  3,  4],  {  it  >  2  })   ! filter([1,  2,  3,  4])  {  it  >  2  } « Functional » interface A bit verbose?
  4. @glaforge — Greach 2014 Implicit closure coercion !6 interface  Predicate

     {          boolean  test(something)   }   ! List  filter(List  l,  Predicate  p)  {          l.findAll  {  p.test(it)  }   }   ! filter([1,  2,  3,  4],  {  it  >  2  }  as  Predicate)   ! filter([1,  2,  3,  4],  {  it  >  2  })   ! filter([1,  2,  3,  4])  {  it  >  2  } « Functional » interface A bit verbose? Implicit closure coercion
  5. @glaforge — Greach 2014 Implicit closure coercion !6 interface  Predicate

     {          boolean  test(something)   }   ! List  filter(List  l,  Predicate  p)  {          l.findAll  {  p.test(it)  }   }   ! filter([1,  2,  3,  4],  {  it  >  2  }  as  Predicate)   ! filter([1,  2,  3,  4],  {  it  >  2  })   ! filter([1,  2,  3,  4])  {  it  >  2  } (it)  -­‐>  it  >  2 « Functional » interface A bit verbose? Implicit closure coercion
  6. @glaforge — Greach 2014 Implicit closure coercion !6 interface  Predicate

     {          boolean  test(something)   }   ! List  filter(List  l,  Predicate  p)  {          l.findAll  {  p.test(it)  }   }   ! filter([1,  2,  3,  4],  {  it  >  2  }  as  Predicate)   ! filter([1,  2,  3,  4],  {  it  >  2  })   ! filter([1,  2,  3,  4])  {  it  >  2  } (it)  -­‐>  it  >  2 « Functional » interface Works with single abstract method classes too A bit verbose? Implicit closure coercion
  7. @glaforge — Greach 2014 @Memoized AST transformation • Piggypack on

    Closure’s own memoization support !8 import  groovy.transform.Memoized   ! @Memoized  int  expensiveOp(int  a,  int  b)  {          sleep  1000          return  a  +  b   }   ! expensiveOp(1,  2)   ! expensiveOp(1,  2)
  8. @glaforge — Greach 2014 @Memoized AST transformation • Piggypack on

    Closure’s own memoization support !8 import  groovy.transform.Memoized   ! @Memoized  int  expensiveOp(int  a,  int  b)  {          sleep  1000          return  a  +  b   }   ! expensiveOp(1,  2)   ! expensiveOp(1,  2) First call takes 1 s
  9. @glaforge — Greach 2014 @Memoized AST transformation • Piggypack on

    Closure’s own memoization support !8 import  groovy.transform.Memoized   ! @Memoized  int  expensiveOp(int  a,  int  b)  {          sleep  1000          return  a  +  b   }   ! expensiveOp(1,  2)   ! expensiveOp(1,  2) First call takes 1 s Subsequent calls return immediately from the cache
  10. @glaforge — Greach 2014 @Memoized AST transformation !9 import  groovy.transform.Memoized

      ! @Memoized   long  fib(long  n)  {          n  <  2  ?  1  :  fib(n-­‐1)  +  fib(n-­‐2)   }   ! fib(40)
  11. @glaforge — Greach 2014 @Memoized AST transformation !9 import  groovy.transform.Memoized

      ! @Memoized   long  fib(long  n)  {          n  <  2  ?  1  :  fib(n-­‐1)  +  fib(n-­‐2)   }   ! fib(40) Handy to cache recursive call results!
  12. @glaforge — Greach 2014 @Memoized AST transformation !9 import  groovy.transform.Memoized

      ! @Memoized   long  fib(long  n)  {          n  <  2  ?  1  :  fib(n-­‐1)  +  fib(n-­‐2)   }   ! fib(40) Handy to cache recursive call results! Instantaneous result
  13. @glaforge — Greach 2014 @Memoized AST transformation !10 fib(7) fib(5)

    fib(6) fib(3) fib(4) fib(4) fib(5) fib(1) fib(2) fib(2) fib(3) fib(2) fib(3) fib(3) fib(4) … … …
  14. @glaforge — Greach 2014 @Memoized AST transformation !11 fib(7) fib(5)

    fib(6) fib(3) fib(4) fib(4) fib(5) fib(1) fib(2) fib(2) fib(3) fib(2) fib(3) fib(3) fib(4) … … …
  15. @glaforge — Greach 2014 @Memoized AST transformation !12 fib(7) fib(5)

    fib(6) fib(3) fib(4) fib(4) fib(5) fib(1) fib(2) fib(2) fib(3) fib(2) fib(3) fib(3) fib(4) … … …
  16. @glaforge — Greach 2014 @Memoized AST transformation !13 fib(7) fib(5)

    fib(6) fib(3) fib(4) fib(4) fib(5) fib(1) fib(2) fib(2) fib(3) fib(2) fib(3) fib(3) fib(4) … … …
  17. @glaforge — Greach 2014 @Memoized AST transformation !14 fib(7) fib(5)

    fib(6) fib(3) fib(4) fib(4) fib(5) fib(1) fib(2) fib(2) fib(3) fib(2) fib(3) fib(3) fib(4) … … …
  18. @glaforge — Greach 2014 @Memoized AST transformation !15 fib(7) fib(5)

    fib(6) fib(3) fib(4) fib(4) fib(5) fib(1) fib(2) fib(2) fib(3) fib(2) fib(3) fib(3) fib(4) … … …
  19. @glaforge — Greach 2014 @Memoized AST transformation !16 fib(7) fib(5)

    fib(6) fib(3) fib(4) fib(4) fib(5) fib(1) fib(2) fib(2) fib(3) fib(2) fib(3) fib(3) fib(4) … … …
  20. @glaforge — Greach 2014 … … … @Memoized AST transformation

    !17 fib(7) fib(5) fib(6) fib(3) fib(4) fib(4) fib(5) fib(1) fib(2) fib(2) fib(3) fib(2) fib(3) fib(3) fib(4)
  21. @glaforge — Greach 2014 … … … @Memoized AST transformation

    !17 fib(7) fib(5) fib(6) fib(3) fib(4) fib(4) fib(5) fib(1) fib(2) fib(2) fib(3) fib(2) fib(3) fib(3) fib(4) Already calculated, in cache!
  22. @glaforge — Greach 2014 @Memoized AST transformation !18 fib(7) fib(5)

    fib(6) fib(3) fib(4) fib(4) fib(5) fib(1) fib(2) fib(2) fib(3) fib(2) fib(3) fib(3) fib(4) … … …
  23. @glaforge — Greach 2014 @Memoized AST transformation !19 fib(7) fib(5)

    fib(6) fib(3) fib(4) fib(4) fib(5) fib(1) fib(2) fib(2) fib(3) fib(2) fib(3) fib(3) fib(4) … … …
  24. @glaforge — Greach 2014 @Memoized AST transformation !20 fib(7) fib(5)

    fib(6) fib(3) fib(4) fib(4) fib(5) fib(1) fib(2) fib(2) fib(3) fib(2) fib(3) fib(3) fib(4) … … …
  25. @glaforge — Greach 2014 @Memoized AST transformation !21 fib(7) fib(5)

    fib(6) fib(3) fib(4) fib(4) fib(5) fib(1) fib(2) fib(2) fib(3) fib(2) fib(3) fib(3) fib(4) … … …
  26. @glaforge — Greach 2014 @Memoized AST transformation !21 fib(7) fib(5)

    fib(6) fib(3) fib(4) fib(4) fib(5) fib(1) fib(2) fib(2) fib(3) fib(2) fib(3) fib(3) fib(4) Much less computation, no abysmal call stack … … …
  27. @glaforge — Greach 2014 Log4j2 @Log variant !22 import  groovy.util.logging.Log4j2

      ! @Log4j2   class  MyClass  {          void  doSomething()  {                  log.info  "did  something  groovy  today!"          }   }
  28. @glaforge — Greach 2014 Log4j2 @Log variant !22 import  groovy.util.logging.Log4j2

      ! @Log4j2   class  MyClass  {          void  doSomething()  {                  log.info  "did  something  groovy  today!"          }   } Just like our other logger implementations, but for Log4j2
  29. @glaforge — Greach 2014 Log4j2 @Log variant !22 import  groovy.util.logging.Log4j2

      ! @Log4j2   class  MyClass  {          void  doSomething()  {                  log.info  "did  something  groovy  today!"          }   } Just like our other logger implementations, but for Log4j2 Log, log, log away…
  30. @glaforge — Greach 2014 Choose which delegated methods to use

    !23 class  Event  {          @Delegate(excludes  =  ['after'])    Date  start          @Delegate(excludes  =  ['before'])  Date  end          String  description   }   ! def  today        =  new  Date().clearTime()   def  nextWeek  =  today  +  7   ! def  event  =  new  Event(description:  'Groovy  conference',                                                          start:  nextWeek,                                                              end:  nextWeek  +  2)   ! assert  event.before(nextWeek  +  1)   assert  !event.before(nextWeek  -­‐  1)   assert  !event.before(today)   ! assert  event.after(today)   assert  event.after(nextWeek  +  1)   assert  !event.after(nextWeek  +  3)
  31. @glaforge — Greach 2014 Choose which delegated methods to use

    !23 class  Event  {          @Delegate(excludes  =  ['after'])    Date  start          @Delegate(excludes  =  ['before'])  Date  end          String  description   }   ! def  today        =  new  Date().clearTime()   def  nextWeek  =  today  +  7   ! def  event  =  new  Event(description:  'Groovy  conference',                                                          start:  nextWeek,                                                              end:  nextWeek  +  2)   ! assert  event.before(nextWeek  +  1)   assert  !event.before(nextWeek  -­‐  1)   assert  !event.before(today)   ! assert  event.after(today)   assert  event.after(nextWeek  +  1)   assert  !event.after(nextWeek  +  3) Exclude certain methods from being delegated
  32. @glaforge — Greach 2014 Choose which delegated methods to use

    !23 class  Event  {          @Delegate(excludes  =  ['after'])    Date  start          @Delegate(excludes  =  ['before'])  Date  end          String  description   }   ! def  today        =  new  Date().clearTime()   def  nextWeek  =  today  +  7   ! def  event  =  new  Event(description:  'Groovy  conference',                                                          start:  nextWeek,                                                              end:  nextWeek  +  2)   ! assert  event.before(nextWeek  +  1)   assert  !event.before(nextWeek  -­‐  1)   assert  !event.before(today)   ! assert  event.after(today)   assert  event.after(nextWeek  +  1)   assert  !event.after(nextWeek  +  3) Exclude certain methods from being delegated Delegate to start date
  33. @glaforge — Greach 2014 Choose which delegated methods to use

    !23 class  Event  {          @Delegate(excludes  =  ['after'])    Date  start          @Delegate(excludes  =  ['before'])  Date  end          String  description   }   ! def  today        =  new  Date().clearTime()   def  nextWeek  =  today  +  7   ! def  event  =  new  Event(description:  'Groovy  conference',                                                          start:  nextWeek,                                                              end:  nextWeek  +  2)   ! assert  event.before(nextWeek  +  1)   assert  !event.before(nextWeek  -­‐  1)   assert  !event.before(today)   ! assert  event.after(today)   assert  event.after(nextWeek  +  1)   assert  !event.after(nextWeek  +  3) Exclude certain methods from being delegated Delegate to start date Delegate to end date
  34. @glaforge — Greach 2014 Annotation-driven base script class definition !25

    import  groovy.transform.BaseScript   ! abstract  class  DeclaredBaseScript  extends  Script  {          int  meaningOfLife  =  42   }
  35. @glaforge — Greach 2014 Annotation-driven base script class definition !25

    import  groovy.transform.BaseScript   ! abstract  class  DeclaredBaseScript  extends  Script  {          int  meaningOfLife  =  42   } Your own Script class extension
  36. @glaforge — Greach 2014 Annotation-driven base script class definition !25

    import  groovy.transform.BaseScript   ! abstract  class  DeclaredBaseScript  extends  Script  {          int  meaningOfLife  =  42   } @BaseScript  DeclaredBaseScript  baseScript   ! assert  meaningOfLife  ==  42 Your own Script class extension
  37. @glaforge — Greach 2014 Annotation-driven base script class definition !25

    import  groovy.transform.BaseScript   ! abstract  class  DeclaredBaseScript  extends  Script  {          int  meaningOfLife  =  42   } @BaseScript  DeclaredBaseScript  baseScript   ! assert  meaningOfLife  ==  42 Declare a variable annotated with @BaseScript, whose type is a subclass of Script Your own Script class extension
  38. @glaforge — Greach 2014 DelegatingScript new base script class •

    Special base script class to delegate method calls and property accesses to a custom object !26 name  =  "Guillaume"   sayHi() class  Person  {          String  name   !        void  sayHi()  {                  println  "Hi  $name"          }   }
  39. @glaforge — Greach 2014 DelegatingScript new base script class •

    Special base script class to delegate method calls and property accesses to a custom object !26 name  =  "Guillaume"   sayHi() class  Person  {          String  name   !        void  sayHi()  {                  println  "Hi  $name"          }   } Your script
  40. @glaforge — Greach 2014 DelegatingScript new base script class •

    Special base script class to delegate method calls and property accesses to a custom object !26 name  =  "Guillaume"   sayHi() class  Person  {          String  name   !        void  sayHi()  {                  println  "Hi  $name"          }   } Your script Delegate property access and method call to this custom class
  41. @glaforge — Greach 2014 DelegatingScript new base script class •

    Special base script class to delegate method calls and property accesses to a custom object !26 name  =  "Guillaume"   sayHi() class  Person  {          String  name   !        void  sayHi()  {                  println  "Hi  $name"          }   } Your script Delegate property access and method call to this custom class How do I do that?
  42. @glaforge — Greach 2014 DelegatingScript new base script class !27

    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"
  43. @glaforge — Greach 2014 DelegatingScript new base script class !27

    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
  44. @glaforge — Greach 2014 DelegatingScript new base script class !27

    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
  45. @glaforge — Greach 2014 DelegatingScript new base script class !27

    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
  46. @glaforge — Greach 2014 DelegatingScript new base script class !27

    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
  47. @glaforge — Greach 2014 DelegatingScript new base script class !27

    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!
  48. @glaforge — Greach 2014 @DelegatesTo with generics type tokens •

    @DelegatesTo help the type checker & IDEs provide better support for DSL using closure delegation !28 @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'          }   }
  49. @glaforge — Greach 2014 @DelegatesTo with generics type tokens •

    @DelegatesTo help the type checker & IDEs provide better support for DSL using closure delegation !28 @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
  50. @glaforge — Greach 2014 @DelegatesTo with generics type tokens •

    @DelegatesTo help the type checker & IDEs provide better support for DSL using closure delegation !28 @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
  51. @glaforge — Greach 2014 @DelegatesTo with generics type tokens •

    @DelegatesTo help the type checker & IDEs provide better support for DSL using closure delegation !28 @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
  52. @glaforge — Greach 2014 Type checking extensions — precompilation •

    Custom type checking extensions can work with compiled extensions as well !30 @TypeChecked(extensions  =  'com.enterprise.MyDslExtension')   void  myBusinessMethod()  {          //  ...   }
  53. @glaforge — Greach 2014 Type checking extensions — precompilation •

    Custom type checking extensions can work with compiled extensions as well !30 @TypeChecked(extensions  =  'com.enterprise.MyDslExtension')   void  myBusinessMethod()  {          //  ...   } Fully qualified name of the extension class
  54. @glaforge — Greach 2014 Type checking extensions — precompilation •

    Custom type checking extensions can work with compiled extensions as well !30 @TypeChecked(extensions  =  'com.enterprise.MyDslExtension')   void  myBusinessMethod()  {          //  ...   } Fully qualified name of the extension class Here, your statically type checked DSL code!
  55. @glaforge — Greach 2014 Type checking extensions — new events

    !31 incompatibleReturnType  {  returnStmt,  inferredReturnType  -­‐>          if  (inferredReturnType  ==  STRING_TYPE)  {                  handled  =  true          }   }
  56. @glaforge — Greach 2014 Type checking extensions — new events

    !31 incompatibleReturnType  {  returnStmt,  inferredReturnType  -­‐>          if  (inferredReturnType  ==  STRING_TYPE)  {                  handled  =  true          }   } incompatibleReturnType event
  57. @glaforge — Greach 2014 Type checking extensions — new events

    !31 incompatibleReturnType  {  returnStmt,  inferredReturnType  -­‐>          if  (inferredReturnType  ==  STRING_TYPE)  {                  handled  =  true          }   } incompatibleReturnType event The referred return type is incompatible with the method’s declared return type
  58. @glaforge — Greach 2014 Type checking extensions — new events

    !31 incompatibleReturnType  {  returnStmt,  inferredReturnType  -­‐>          if  (inferredReturnType  ==  STRING_TYPE)  {                  handled  =  true          }   } incompatibleReturnType event The referred return type is incompatible with the method’s declared return type Assume that if the inferred return type is String, then it’s correct (the DSL handles it)
  59. @glaforge — Greach 2014 Type checking extensions — new events

    !32 ambiguousMethods  {  methods,  origin  -­‐>          methods.find  {  it.parameters.any  {                    it.type  ==  classNodeFor(Integer)  }            }   }
  60. @glaforge — Greach 2014 Type checking extensions — new events

    !32 ambiguousMethods  {  methods,  origin  -­‐>          methods.find  {  it.parameters.any  {                    it.type  ==  classNodeFor(Integer)  }            }   } ambiguousMethods event
  61. @glaforge — Greach 2014 Type checking extensions — new events

    !32 ambiguousMethods  {  methods,  origin  -­‐>          methods.find  {  it.parameters.any  {                    it.type  ==  classNodeFor(Integer)  }            }   } ambiguousMethods event If one of the methods takes an Integer argument, pick this one
  62. @glaforge — Greach 2014 Type checking extensions — dynamic calls

    • New makeDynamic() method to make calls dynamic !33 methodNotFound  {  receiver,  name,  argumentList,  argTypes,  call  -­‐>          return  makeDynamic(call,  int_TYPE)   }   ! unresolvedProperty  {  pexp  -­‐>          def  lhs  =  getType(pexp.objectExpression)          if  (lhs==classNodeFor(MetaClass))  {                  makeDynamic(pexp,  CLOSURE_TYPE)          }  else  {                  makeDynamic(pexp,  int_TYPE)          }   }   ! unresolvedAttribute  {  pexp  -­‐>          makeDynamic(pexp,  int_TYPE)   }   ! unresolvedVariable  {  var  -­‐>          makeDynamic(var,  int_TYPE)   }
  63. @glaforge — Greach 2014 Type checking extensions — dynamic calls

    • New makeDynamic() method to make calls dynamic !33 methodNotFound  {  receiver,  name,  argumentList,  argTypes,  call  -­‐>          return  makeDynamic(call,  int_TYPE)   }   ! unresolvedProperty  {  pexp  -­‐>          def  lhs  =  getType(pexp.objectExpression)          if  (lhs==classNodeFor(MetaClass))  {                  makeDynamic(pexp,  CLOSURE_TYPE)          }  else  {                  makeDynamic(pexp,  int_TYPE)          }   }   ! unresolvedAttribute  {  pexp  -­‐>          makeDynamic(pexp,  int_TYPE)   }   ! unresolvedVariable  {  var  -­‐>          makeDynamic(var,  int_TYPE)   } Unresolved methods, properties, attributes, or variables can be made dynamic
  64. @glaforge — Greach 2014 Type checking extensions — dynamic calls

    • New makeDynamic() method to make calls dynamic !33 methodNotFound  {  receiver,  name,  argumentList,  argTypes,  call  -­‐>          return  makeDynamic(call,  int_TYPE)   }   ! unresolvedProperty  {  pexp  -­‐>          def  lhs  =  getType(pexp.objectExpression)          if  (lhs==classNodeFor(MetaClass))  {                  makeDynamic(pexp,  CLOSURE_TYPE)          }  else  {                  makeDynamic(pexp,  int_TYPE)          }   }   ! unresolvedAttribute  {  pexp  -­‐>          makeDynamic(pexp,  int_TYPE)   }   ! unresolvedVariable  {  var  -­‐>          makeDynamic(var,  int_TYPE)   } Unresolved methods, properties, attributes, or variables can be made dynamic Use with care!
  65. @glaforge — Greach 2014 Remove part of strings with a

    regex !35 assert  ('Hello  Groovy  world!'  -­‐  ~/\s+Gr\w+/)                            ==  'Hello  world!'
  66. @glaforge — Greach 2014 Remove part of strings with a

    regex !35 assert  ('Hello  Groovy  world!'  -­‐  ~/\s+Gr\w+/)                            ==  'Hello  world!' A String
  67. @glaforge — Greach 2014 Remove part of strings with a

    regex !35 assert  ('Hello  Groovy  world!'  -­‐  ~/\s+Gr\w+/)                            ==  'Hello  world!' A String A Pattern
  68. @glaforge — Greach 2014 Remove part of strings with a

    regex !35 assert  ('Hello  Groovy  world!'  -­‐  ~/\s+Gr\w+/)                            ==  'Hello  world!' A String A Pattern Matched string fragment removed!
  69. @glaforge — Greach 2014 Lots of new methods for Iterables

    !36 class  Counter  implements  Iterable  {          private  Integer  counter  =  0          Iterator  iterator()  {                  [hasNext:  {  counter  <=  10  },                          next:  {  counter++  }]  as  Iterator          }   }
  70. @glaforge — Greach 2014 Lots of new methods for Iterables

    !36 class  Counter  implements  Iterable  {          private  Integer  counter  =  0          Iterator  iterator()  {                  [hasNext:  {  counter  <=  10  },                          next:  {  counter++  }]  as  Iterator          }   } assert  new  Counter().sum()  ==  55   assert  new  Counter().min()  ==  0   assert  new  Counter().max()  ==  10   assert  new  Counter().count(2)  ==  1   assert  new  Counter().count  {  it  %  2  ==  0  }  ==  6   assert  new  Counter().collectMany  {  [it  *  2]  }  ==                                  [0,  2,  4,  6,  8,  10,  12,  14,  16,  18,  20]   assert  new  Counter().groupBy  {  it  %  2  ==  0  ?  'even'  :  'odd'  }  ==                                  [even:[0,  2,  4,  6,  8,  10],  odd:[1,  3,  5,  7,  9]]
  71. @glaforge — Greach 2014 Lots of new methods for Iterables

    !36 class  Counter  implements  Iterable  {          private  Integer  counter  =  0          Iterator  iterator()  {                  [hasNext:  {  counter  <=  10  },                          next:  {  counter++  }]  as  Iterator          }   } assert  new  Counter().sum()  ==  55   assert  new  Counter().min()  ==  0   assert  new  Counter().max()  ==  10   assert  new  Counter().count(2)  ==  1   assert  new  Counter().count  {  it  %  2  ==  0  }  ==  6   assert  new  Counter().collectMany  {  [it  *  2]  }  ==                                  [0,  2,  4,  6,  8,  10,  12,  14,  16,  18,  20]   assert  new  Counter().groupBy  {  it  %  2  ==  0  ?  'even'  :  'odd'  }  ==                                  [even:[0,  2,  4,  6,  8,  10],  odd:[1,  3,  5,  7,  9]] Collections are also Iterable
  72. @glaforge — Greach 2014 @Immutable with copyWith() method !37 import

     groovy.transform.Immutable   ! @Immutable(copyWith  =  true)   class  User  {          String  name          String  email   }   ! def  jdEx  =  new  User('John  Doe',  '[email protected]')   ! def  jdGmail  =  jdEx.copyWith(email:  '[email protected]')   ! jdGmail.with  {          assert  name  ==  'John  Doe'          assert  email  ==  '[email protected]'   }
  73. @glaforge — Greach 2014 @Immutable with copyWith() method !37 import

     groovy.transform.Immutable   ! @Immutable(copyWith  =  true)   class  User  {          String  name          String  email   }   ! def  jdEx  =  new  User('John  Doe',  '[email protected]')   ! def  jdGmail  =  jdEx.copyWith(email:  '[email protected]')   ! jdGmail.with  {          assert  name  ==  'John  Doe'          assert  email  ==  '[email protected]'   } Specify you want the copyWith() method
  74. @glaforge — Greach 2014 @Immutable with copyWith() method !37 import

     groovy.transform.Immutable   ! @Immutable(copyWith  =  true)   class  User  {          String  name          String  email   }   ! def  jdEx  =  new  User('John  Doe',  '[email protected]')   ! def  jdGmail  =  jdEx.copyWith(email:  '[email protected]')   ! jdGmail.with  {          assert  name  ==  'John  Doe'          assert  email  ==  '[email protected]'   } Specify you want the copyWith() method New immutable user with a different email
  75. @glaforge — Greach 2014 set() & copyWith() for Date &

    Calendar !38 import  static  java.util.Calendar.MARCH   ! def  date  =  new  Date().clearTime()   date.set(year:  2014,  month:  MARCH,  date:  28)   ! def  yearLater  =  date.copyWith(year:  2015)   assert  yearLater.format('dd-­‐MM-­‐yyyy')  ==  '28-­‐03-­‐2015'
  76. @glaforge — Greach 2014 set() & copyWith() for Date &

    Calendar !38 import  static  java.util.Calendar.MARCH   ! def  date  =  new  Date().clearTime()   date.set(year:  2014,  month:  MARCH,  date:  28)   ! def  yearLater  =  date.copyWith(year:  2015)   assert  yearLater.format('dd-­‐MM-­‐yyyy')  ==  '28-­‐03-­‐2015' Mutate
  77. @glaforge — Greach 2014 set() & copyWith() for Date &

    Calendar !38 import  static  java.util.Calendar.MARCH   ! def  date  =  new  Date().clearTime()   date.set(year:  2014,  month:  MARCH,  date:  28)   ! def  yearLater  =  date.copyWith(year:  2015)   assert  yearLater.format('dd-­‐MM-­‐yyyy')  ==  '28-­‐03-­‐2015' def  cal  =  Calendar.instance   cal.set(year:  2014,  month:  MARCH,  date:  26)   ! def  newCalendar  =  cal.copyWith(date:  27)   assert  newCalendar.format('dd-­‐MM-­‐yyyy')  ==  '27-­‐03-­‐2014' Mutate
  78. @glaforge — Greach 2014 set() & copyWith() for Date &

    Calendar !38 import  static  java.util.Calendar.MARCH   ! def  date  =  new  Date().clearTime()   date.set(year:  2014,  month:  MARCH,  date:  28)   ! def  yearLater  =  date.copyWith(year:  2015)   assert  yearLater.format('dd-­‐MM-­‐yyyy')  ==  '28-­‐03-­‐2015' def  cal  =  Calendar.instance   cal.set(year:  2014,  month:  MARCH,  date:  26)   ! def  newCalendar  =  cal.copyWith(date:  27)   assert  newCalendar.format('dd-­‐MM-­‐yyyy')  ==  '27-­‐03-­‐2014' Mutate Clone and mutate
  79. @glaforge — Greach 2014 Loop between Date & Calendar date

    points !39 def  today  =  new  Date().clearTime()   def  nextWeek  =  today  +  7   ! today.upto(nextWeek)  {          println  it.format('dd  MMMM')   }
  80. @glaforge — Greach 2014 Loop between Date & Calendar date

    points !39 def  today  =  new  Date().clearTime()   def  nextWeek  =  today  +  7   ! today.upto(nextWeek)  {          println  it.format('dd  MMMM')   } Iterate between dates with upto() and downto()
  81. @glaforge — Greach 2014 Loop between Date & Calendar date

    points !39 def  today  =  new  Date().clearTime()   def  nextWeek  =  today  +  7   ! today.upto(nextWeek)  {          println  it.format('dd  MMMM')   } def  to  =  Calendar.instance   to.set(year:  2014,  month:  Calendar.MARCH,  date:  10)   ! def  from  =  Calendar.instance   from.set(year:  2014,  month:  Calendar.MARCH,  date:  28)   ! from.downto(to)  {          println  it.format('dd  MMMM')   } Iterate between dates with upto() and downto()
  82. @glaforge — Greach 2014 Loop between Date & Calendar date

    points !39 def  today  =  new  Date().clearTime()   def  nextWeek  =  today  +  7   ! today.upto(nextWeek)  {          println  it.format('dd  MMMM')   } def  to  =  Calendar.instance   to.set(year:  2014,  month:  Calendar.MARCH,  date:  10)   ! def  from  =  Calendar.instance   from.set(year:  2014,  month:  Calendar.MARCH,  date:  28)   ! from.downto(to)  {          println  it.format('dd  MMMM')   } Iterate between dates with upto() and downto() upto() and downto() work with Calendars too
  83. @glaforge — Greach 2014 Groovysh enhancements — doc command !41

    Launches your browser with the JavaDoc and GDK doc of the class
  84. @glaforge — Greach 2014 Bintray JCenter repository • JFrog’s Bintray

    JCenter first in 
 the resolver chain for your @Grab statements ! – faster and more responsive 
 than Maven Central – always proper dependencies with checksums – stores and caches dependencies coming from Maven Central if not initially available !43
  85. @glaforge — Greach 2014 Super fast JSON support! ! •

    New parsers and builders have been contributed – by Rick Hightower & Andrey Bloschetsov ! • Making Groovy serialization / deserialization faster than – GSON – Jackson !45
  86. @glaforge — Greach 2014 A new template engine, markup based

    !46 import  groovy.text.markup.*   ! MarkupTemplateEngine  engine  =  new  MarkupTemplateEngine(          new  TemplateConfiguration())   def  template  =  engine.createTemplate  '''          html  {                  head  {                          include  template:  'header.gtpl'                  }                  body  {                          p  "Hello  Greach"                  }          }   '''   System.out  <<  template.make()
  87. @glaforge — Greach 2014 A new template engine, markup based

    !46 import  groovy.text.markup.*   ! MarkupTemplateEngine  engine  =  new  MarkupTemplateEngine(          new  TemplateConfiguration())   def  template  =  engine.createTemplate  '''          html  {                  head  {                          include  template:  'header.gtpl'                  }                  body  {                          p  "Hello  Greach"                  }          }   '''   System.out  <<  template.make() Type-checked models, bytecode-compiled templates, includes, custom indentation, (un)escaping, i18n support, and more
  88. @glaforge — Greach 2014 Traits !47 trait  FlyingAbility  {  

           String  fly()  {                  "I  believe  I  can  fly!"          }   }
  89. @glaforge — Greach 2014 Traits !47 trait  FlyingAbility  {  

           String  fly()  {                  "I  believe  I  can  fly!"          }   } A trait keyword applying the @Trait transformation
  90. @glaforge — Greach 2014 Traits !47 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!"
  91. @glaforge — Greach 2014 Traits characteristics • Groovy traits are

    stateful – Java 8’s default methods won’t cut it here ! • Precedence: When implementing several traits, 
 first declared trait wins – in case both traits have a method with the same signature ! • Supports runtime mixing of traits with ‘as’ !48
  92. @glaforge — Greach 2014 Stateful traits !49 trait  Named  {

             String  name   }   ! class  Phone  implements  Named  {}   ! def  phone  =  new  Phone(name:  'Galaxy  S3')   assert  phone.name  ==  'Galaxy  S3'
  93. @glaforge — Greach 2014 Stateful traits !49 trait  Named  {

             String  name   }   ! class  Phone  implements  Named  {}   ! def  phone  =  new  Phone(name:  'Galaxy  S3')   assert  phone.name  ==  'Galaxy  S3' A usual Groovy property!
  94. @glaforge — Greach 2014 Trait inheritance !50 trait  Named  {

             String  name   }   ! trait  NameSpeakable  implements  Named  {          String  speak()  {  "My  name  is  ${name}"  }   }   ! class  Phone  implements  NamedSpeakable  {}   ! def  phone  =  new  Phone(name:  'Galaxy  S3')   assert  phone.speak()  ==  'My  name  is  Galaxy  S3'
  95. @glaforge — Greach 2014 Trait inheritance !50 trait  Named  {

             String  name   }   ! trait  NameSpeakable  implements  Named  {          String  speak()  {  "My  name  is  ${name}"  }   }   ! class  Phone  implements  NamedSpeakable  {}   ! def  phone  =  new  Phone(name:  'Galaxy  S3')   assert  phone.speak()  ==  'My  name  is  Galaxy  S3' Implement the parent trait
  96. @glaforge — Greach 2014 Runtime traits !51 trait  Flying  {

             String  fly()  {  "I'm  flying!"  }   }   ! class  Duck  {}   def  d  =  new  Duck()  as  Flying   ! assert  d  instanceof  Flying   assert  d.fly()  ==  "I'm  flying!"
  97. @glaforge — Greach 2014 Runtime traits !51 trait  Flying  {

             String  fly()  {  "I'm  flying!"  }   }   ! class  Duck  {}   def  d  =  new  Duck()  as  Flying   ! assert  d  instanceof  Flying   assert  d.fly()  ==  "I'm  flying!" Implement Flying trait at runtime
  98. @glaforge — Greach 2014 @TailRecursive transformation !52 @groovy.transform.TailRecursive   def

     fact(n,  accu  =  1G)  {          if  (n  <  2)  accu          else  fact(n  -­‐  1,  n  *  accu)   }
  99. @glaforge — Greach 2014 @TailRecursive transformation !52 @groovy.transform.TailRecursive   def

     fact(n,  accu  =  1G)  {          if  (n  <  2)  accu          else  fact(n  -­‐  1,  n  *  accu)   } https://github.com/jlink/tailrec
  100. @glaforge — Greach 2014 @TailRecursive transformation !52 @groovy.transform.TailRecursive   def

     fact(n,  accu  =  1G)  {          if  (n  <  2)  accu          else  fact(n  -­‐  1,  n  *  accu)   } https://github.com/jlink/tailrec Transformation applied to methods, not closures
  101. @glaforge — Greach 2014 New website and documentation • New

    reference documentation and
 guides, using AsciiDoctor ! • New website with a 
 refreshed skin and the 
 new content !53
  102. @glaforge — Greach 2014 New website and documentation • New

    reference documentation and
 guides, using AsciiDoctor ! • New website with a 
 refreshed skin and the 
 new content !53 Looking for contributions!
  103. @glaforge — Greach 2014 GroovyDoc template overhaul !54 GroovyDoc !=

    Sexy Doc Would also be nice for Groovy GDK ocumentation
  104. @glaforge — Greach 2014 Finer-grained implicit closure coercion !56 interface

     Action  {          void  act()   }   ! void  atomic(Action  a)  {          a.act()   }
  105. @glaforge — Greach 2014 Finer-grained implicit closure coercion !56 interface

     Action  {          void  act()   }   ! void  atomic(Action  a)  {          a.act()   } atomic  {  println  "hi"  }
  106. @glaforge — Greach 2014 Finer-grained implicit closure coercion !56 interface

     Action  {          void  act()   }   ! void  atomic(Action  a)  {          a.act()   } interface  ParameterizedAction  {          void  execute(int  i)   }   ! void  atomic(ParameterizedAction  pa)  {          pa.execute(1)   } atomic  {  println  "hi"  }
  107. @glaforge — Greach 2014 Finer-grained implicit closure coercion !56 interface

     Action  {          void  act()   }   ! void  atomic(Action  a)  {          a.act()   } interface  ParameterizedAction  {          void  execute(int  i)   }   ! void  atomic(ParameterizedAction  pa)  {          pa.execute(1)   } atomic  {  println  "hi"  } We’d get an ambiguous method exception
  108. @glaforge — Greach 2014 Finer-grained implicit closure coercion !56 interface

     Action  {          void  act()   }   ! void  atomic(Action  a)  {          a.act()   } interface  ParameterizedAction  {          void  execute(int  i)   }   ! void  atomic(ParameterizedAction  pa)  {          pa.execute(1)   } atomic  {  println  "hi"  } atomic  {  int  i  -­‐>  println  "hi  $i"  } We’d get an ambiguous method exception
  109. @glaforge — Greach 2014 Finer-grained implicit closure coercion !56 interface

     Action  {          void  act()   }   ! void  atomic(Action  a)  {          a.act()   } interface  ParameterizedAction  {          void  execute(int  i)   }   ! void  atomic(ParameterizedAction  pa)  {          pa.execute(1)   } atomic  {  println  "hi"  } atomic  {  int  i  -­‐>  println  "hi  $i"  } We’d get an ambiguous method exception Finer grained coercion to distinguish correct coercion depending on closure’s arguments
  110. @glaforge — Greach 2014 Goals for the new Meta-Object Protocol

    • Fully leverage and build upon JDK 7+ invoke dynamic – get Java-like performance even for dynamic code • Rationalize the sedimentation of meta-programming – more coherence, less corner cases & inconsistencies • Provide a notion of « realm » – shield users of « monkey patching » – finer-grained control of meta-programming reach • Private visibility anyone? !60
  111. @glaforge — Greach 2014 Antlr v4 grammar • Problems –

    Groovy still uses Antlr v2! •but version 3 and 4 are out – Groovy’s grammar evolved from a Java grammar •harder to fix and evolve, especially with Antlr v2 • Advantages – Easier to start from a clean slate – Antlr 4 more tolerant and powerful regarding ambiguities – Time to clean some grammar & syntax warts! – Need to implement the Java 8 constructs! !62
  112. @glaforge — Greach 2014 Antlr v4 grammar • Problems –

    Groovy still uses Antlr v2! •but version 3 and 4 are out – Groovy’s grammar evolved from a Java grammar •harder to fix and evolve, especially with Antlr v2 • Advantages – Easier to start from a clean slate – Antlr 4 more tolerant and powerful regarding ambiguities – Time to clean some grammar & syntax warts! – Need to implement the Java 8 constructs! !62
  113. @glaforge — Greach 2014 Java 8 support • Additional grammar

    and semantics features to support – to keep saying Groovy / Java interop is awesome! ! • New in Java 8 – lambdas – method references – default methods in interfaces – stream API, date / time API – annotations on types & repeated annotations !64