Lift off with Groovy 2 at JavaOne 2013

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

description

Presentations on the features of the Groovy 2.x line

Transcript of Lift off with Groovy 2 at JavaOne 2013

Page 1: Lift off with Groovy 2 at JavaOne 2013

© 2013 Guillaume Laforge. All rights reserved. Do not distribute without permission.

Guillaume Laforge @glaforge

Lift-off with Groovy 2 ...and beyond!

Page 2: Lift off with Groovy 2 at JavaOne 2013

© 2013 Guillaume Laforge. All rights reserved. Do not distribute without permission.

Guillaume Laforge @glaforge

Lift-off with Groovy 2 ...and beyond!

Page 3: Lift off with Groovy 2 at JavaOne 2013

Guillaume Laforge @glaforge

http://glaforge.appspot.com http://gplus.to/glaforge

Page 4: Lift off with Groovy 2 at JavaOne 2013

Guillaume Laforge @glaforge

http://glaforge.appspot.com http://gplus.to/glaforge

Presentation will be uploaded tohttps://speakerdeck.com/glaforge

Page 5: Lift off with Groovy 2 at JavaOne 2013

A dynamic language,optionally typed

Groovy

Page 6: Lift off with Groovy 2 at JavaOne 2013

...statically type checkedand compiled as needed

Groovy

Page 7: Lift off with Groovy 2 at JavaOne 2013

Syntax deriving from Java, thus easy to learn

Groovy

Page 8: Lift off with Groovy 2 at JavaOne 2013

million downloadsin 2012

1.7

Page 9: Lift off with Groovy 2 at JavaOne 2013
Page 10: Lift off with Groovy 2 at JavaOne 2013

10

Page 11: Lift off with Groovy 2 at JavaOne 2013

A blossomingEcosystem

Page 12: Lift off with Groovy 2 at JavaOne 2013
Page 13: Lift off with Groovy 2 at JavaOne 2013
Page 14: Lift off with Groovy 2 at JavaOne 2013
Page 15: Lift off with Groovy 2 at JavaOne 2013
Page 16: Lift off with Groovy 2 at JavaOne 2013

GVM

Page 17: Lift off with Groovy 2 at JavaOne 2013

Let’s start the engine

ModularityJava 7: Project Coin & invoke dynamicStatic type checking & compilation

Page 18: Lift off with Groovy 2 at JavaOne 2013

Modularity

« Not everybody needs everything,all the time, at the same time! »

Page 19: Lift off with Groovy 2 at JavaOne 2013

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

Page 20: Lift off with Groovy 2 at JavaOne 2013

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

Page 21: Lift off with Groovy 2 at JavaOne 2013

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

Page 22: Lift off with Groovy 2 at JavaOne 2013

« Let’s go shopping »

Page 23: Lift off with Groovy 2 at JavaOne 2013

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

Page 24: Lift off with Groovy 2 at JavaOne 2013

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

Page 25: Lift off with Groovy 2 at JavaOne 2013

Extension modules

• Create your own extension module– contribute static methods

20

package  foo

class  StaticStringExtension  {        static  hi(String  self)  {                "Hi!"        }}//  usage:  String.hi()

Page 26: Lift off with Groovy 2 at JavaOne 2013

Extension module descriptor

• META-INF/– services/

• org.codehaus.groovy.runtime.ExtensionModule

moduleName  =  stringExtensionsmoduleVersion  =  1.0//  comma  separated  list  of  FQN  class  namesextensionClasses  =  foo.StringExtension//  comma  separated  list  of  FQN  class  namesstaticExtensionClasses  =  foo.StaticStringExtension

21

Page 27: Lift off with Groovy 2 at JavaOne 2013

Java 7 theme

« Project Coin » syntaxInvoke Dynamic support

Page 28: Lift off with Groovy 2 at JavaOne 2013

Binary literals

• In addition to decimal, octal and hexa• A new binary representation:

int  x  =  0b10101111assert  x  ==  175  byte  aByte  =  0b00100001assert  aByte  ==  33  int  anInt  =  0b1010000101000101assert  anInt  ==  41285

23

Page 29: Lift off with Groovy 2 at JavaOne 2013
Page 30: Lift off with Groovy 2 at JavaOne 2013

Underscores in literals

• Use underscores in number literals

long  creditCardNumber  =  1234_5678_9012_3456Llong  socialSecurityNumbers  =  999_99_9999Lfloat  monetaryAmount  =  12_345_132.12long  hexBytes  =  0xFF_EC_DE_5Elong  hexWords  =  0xFFEC_DE5Elong  maxLong  =  0x7fff_ffff_ffff_ffffLlong  alsoMaxLong  =  9_223_372_036_854_775_807Llong  bytes  =  0b11010010_01101001_10010100_10010010

25

Page 31: Lift off with Groovy 2 at JavaOne 2013

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

Page 32: Lift off with Groovy 2 at JavaOne 2013

Woot!

Page 33: Lift off with Groovy 2 at JavaOne 2013

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

Page 34: Lift off with Groovy 2 at JavaOne 2013

A « static » theme

Static type checkingStatic compilation

Page 35: Lift off with Groovy 2 at JavaOne 2013

Static type checking

• Goal: make the compiler grumpy!

– throw errors at compile-time• rather than at runtime

30

Page 36: Lift off with Groovy 2 at JavaOne 2013

We don’t need dynamic features

all the time!

Page 37: Lift off with Groovy 2 at JavaOne 2013

We don’t need dynamic features

all the time!

Nah !

Page 38: Lift off with Groovy 2 at JavaOne 2013

Static type checking

• A « grumpy » compiler should...

– say when there’s a typoin a method or variable name

– complain when a non-existent method is called

– or on bad assignments or use a bad return type

32

Page 39: Lift off with Groovy 2 at JavaOne 2013

Static type checking

• The compiler should infer types...

– less explicit types and casts

– fine grained type inference•« flow typing »•« lowest upper bound »

33

Page 40: Lift off with Groovy 2 at JavaOne 2013

Static type checking

• But the compiler should understand extension methods

– allows a good level of dynamism, despite the additional restrictions

34

Page 41: Lift off with Groovy 2 at JavaOne 2013

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

Page 42: Lift off with Groovy 2 at JavaOne 2013

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

Page 43: Lift off with Groovy 2 at JavaOne 2013

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

Page 44: Lift off with Groovy 2 at JavaOne 2013

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

Page 45: Lift off with Groovy 2 at JavaOne 2013

Wrong variable assignments

//  cannot  assign  value  of  type...  to  variable...int  x  =  new  Object()Set  set  =  new  Object()  String[]  strings  =  ['a','b','c']int  str  =  strings[0]  //  cannot  find  matching  method  plus()int  i  =  0i  +=  '1'

36

Page 46: Lift off with Groovy 2 at JavaOne 2013

Wrong variable assignments

//  cannot  assign  value  of  type...  to  variable...int  x  =  new  Object()Set  set  =  new  Object()  String[]  strings  =  ['a','b','c']int  str  =  strings[0]  //  cannot  find  matching  method  plus()int  i  =  0i  +=  '1'

Compilation error

36

Page 47: Lift off with Groovy 2 at JavaOne 2013

Wrong variable assignments

//  cannot  assign  value  of  type...  to  variable...int  x  =  new  Object()Set  set  =  new  Object()  String[]  strings  =  ['a','b','c']int  str  =  strings[0]  //  cannot  find  matching  method  plus()int  i  =  0i  +=  '1'

Compilation error

Compilation error

36

Page 48: Lift off with Groovy 2 at JavaOne 2013

Wrong variable assignments

//  cannot  assign  value  of  type...  to  variable...int  x  =  new  Object()Set  set  =  new  Object()  String[]  strings  =  ['a','b','c']int  str  =  strings[0]  //  cannot  find  matching  method  plus()int  i  =  0i  +=  '1'

Compilation error

Compilation error

Compilation error

36

Page 49: Lift off with Groovy 2 at JavaOne 2013

Wrong return type

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

37

Page 50: Lift off with Groovy 2 at JavaOne 2013

Wrong return type

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

Compilation error

37

Page 51: Lift off with Groovy 2 at JavaOne 2013

Wrong return type

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

Compilation error

In the end, call StringBuilder’s toString()

37

Page 52: Lift off with Groovy 2 at JavaOne 2013

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

Page 53: Lift off with Groovy 2 at JavaOne 2013

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

Page 54: Lift off with Groovy 2 at JavaOne 2013

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

Page 55: Lift off with Groovy 2 at JavaOne 2013

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

Page 56: Lift off with Groovy 2 at JavaOne 2013

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

Page 57: Lift off with Groovy 2 at JavaOne 2013

Mix dynamic & statically checked code

@TypeCheckedString  greeting(String  name)  {        //  call  method  with  dynamic  behavior        //  but  with  proper  signature        generateMarkup(name.toUpperCase())}  //  usual  dynamic  behaviorString  generateMarkup(String  name)  {        def  sw  =  new  StringWriter()        new  MarkupBuilder(sw).html  {                body  {                        div  name                }        }        sw.toString()}

39

Page 58: Lift off with Groovy 2 at JavaOne 2013

Mix dynamic & statically checked code

@TypeCheckedString  greeting(String  name)  {        //  call  method  with  dynamic  behavior        //  but  with  proper  signature        generateMarkup(name.toUpperCase())}  //  usual  dynamic  behaviorString  generateMarkup(String  name)  {        def  sw  =  new  StringWriter()        new  MarkupBuilder(sw).html  {                body  {                        div  name                }        }        sw.toString()}

Statically checked

39

Page 59: Lift off with Groovy 2 at JavaOne 2013

Mix dynamic & statically checked code

@TypeCheckedString  greeting(String  name)  {        //  call  method  with  dynamic  behavior        //  but  with  proper  signature        generateMarkup(name.toUpperCase())}  //  usual  dynamic  behaviorString  generateMarkup(String  name)  {        def  sw  =  new  StringWriter()        new  MarkupBuilder(sw).html  {                body  {                        div  name                }        }        sw.toString()}

Statically checked

Dynamic

39

Page 60: Lift off with Groovy 2 at JavaOne 2013

Instanceof checks

@TypeChecked  void  test(Object  val)  {

       if  (val  instanceof  String)  {                println  val.toUpperCase()        }  else  if  (val  instanceof  Number)  {                println  "X"  *  val.intValue()        }}

40

Page 61: Lift off with Groovy 2 at JavaOne 2013

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

Page 62: Lift off with Groovy 2 at JavaOne 2013

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

Page 63: Lift off with Groovy 2 at JavaOne 2013

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

Page 64: Lift off with Groovy 2 at JavaOne 2013

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

Page 65: Lift off with Groovy 2 at JavaOne 2013

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

Page 66: Lift off with Groovy 2 at JavaOne 2013

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

Page 67: Lift off with Groovy 2 at JavaOne 2013

Not really clean, your code!

Page 68: Lift off with Groovy 2 at JavaOne 2013

Not really clean, your code!

Grmmpf...no!

Page 69: Lift off with Groovy 2 at JavaOne 2013

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

Page 70: Lift off with Groovy 2 at JavaOne 2013

But if it ain’t dynamic, can we compile

it statically?

Page 71: Lift off with Groovy 2 at JavaOne 2013

But if it ain’t dynamic, can we compile

it statically?

But of course!!!

Page 72: Lift off with Groovy 2 at JavaOne 2013

Static compilation

• Given the code is statically type checked, lots of type information was infered...so we can as well compile statically !

– ie. generate the same bytecode as javac

• Also interesting when stuck on JDK < 7to gain performance improvements

46

Page 73: Lift off with Groovy 2 at JavaOne 2013

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

Page 74: Lift off with Groovy 2 at JavaOne 2013

I canz do what I want wiz your code

Page 75: Lift off with Groovy 2 at JavaOne 2013

I canz do what I want wiz your code

Niark !

Page 76: Lift off with Groovy 2 at JavaOne 2013

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

Page 77: Lift off with Groovy 2 at JavaOne 2013

Mix statically compiled code with dynamic

@CompileStaticString  greeting(String  name)  {        //  call  method  with  dynamic  behavior        //  but  with  proper  signature        generateMarkup(name.toUpperCase())}  //  usual  dynamic  behaviorString  generateMarkup(String  name)  {        def  sw  =  new  StringWriter()        new  MarkupBuilder(sw).html  {                body  {                        div  name                }        }        sw.toString()}

50

Page 78: Lift off with Groovy 2 at JavaOne 2013

Mix statically compiled code with dynamic

@CompileStaticString  greeting(String  name)  {        //  call  method  with  dynamic  behavior        //  but  with  proper  signature        generateMarkup(name.toUpperCase())}  //  usual  dynamic  behaviorString  generateMarkup(String  name)  {        def  sw  =  new  StringWriter()        new  MarkupBuilder(sw).html  {                body  {                        div  name                }        }        sw.toString()}

Statically compiled

50

Page 79: Lift off with Groovy 2 at JavaOne 2013

Mix statically compiled code with dynamic

@CompileStaticString  greeting(String  name)  {        //  call  method  with  dynamic  behavior        //  but  with  proper  signature        generateMarkup(name.toUpperCase())}  //  usual  dynamic  behaviorString  generateMarkup(String  name)  {        def  sw  =  new  StringWriter()        new  MarkupBuilder(sw).html  {                body  {                        div  name                }        }        sw.toString()}

Statically compiled

Dynamic

50

Page 80: Lift off with Groovy 2 at JavaOne 2013

Mix statically compiled code with dynamic

@CompileStaticString  greeting(String  name)  {        //  call  method  with  dynamic  behavior        //  but  with  proper  signature        generateMarkup(name.toUpperCase())}  //  usual  dynamic  behaviorString  generateMarkup(String  name)  {        def  sw  =  new  StringWriter()        new  MarkupBuilder(sw).html  {                body  {                        div  name                }        }        sw.toString()}

Statically compiled

Dynamic

Call a method with

dynamic content

50

Page 81: Lift off with Groovy 2 at JavaOne 2013

Mix statically compiled code with dynamic

@CompileStaticString  greeting(String  name)  {        //  call  method  with  dynamic  behavior        //  but  with  proper  signature        generateMarkup(name.toUpperCase())}  //  usual  dynamic  behaviorString  generateMarkup(String  name)  {        def  sw  =  new  StringWriter()        new  MarkupBuilder(sw).html  {                body  {                        div  name                }        }        sw.toString()}

Statically compiled

Dynamic

Call a method with

dynamic content

Method signatures are a contract!

50

Page 82: Lift off with Groovy 2 at JavaOne 2013

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

Page 83: Lift off with Groovy 2 at JavaOne 2013

What about performance?

Fibonacci Pi (π) quadrature

Binarytrees

Java

Staticcompilation

Primitive optimizations

No prim.optimizations

191 ms 97 ms 3.6 s

197 ms 101 ms 4.3 s

360 ms 111 ms 23.7 s

2590 ms 3220 ms 50.0 s1.7

1.8

2.x

52

Page 84: Lift off with Groovy 2 at JavaOne 2013

...and now, ontoGroovy 2.1

Complete Invoke Dynamic supportMeta-annotationsAdvanced compiler configurationType checker extensions

Page 85: Lift off with Groovy 2 at JavaOne 2013

Invoke Dynamic

Complete support of Invoke Dynamic

Page 86: Lift off with Groovy 2 at JavaOne 2013

Meta-annotations

One annotationto rule them all!

Page 87: Lift off with Groovy 2 at JavaOne 2013

Meta-annotations

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

• And which work with AST transformations

56

Page 88: Lift off with Groovy 2 at JavaOne 2013

Meta-annotations

@Immutable@ToString(excludes  =  ["age"])@AnnotationCollector@interface  MyAlias  {}

57

Page 89: Lift off with Groovy 2 at JavaOne 2013

Meta-annotations

@Immutable@ToString(excludes  =  ["age"])@AnnotationCollector@interface  MyAlias  {}

Collected annotations

57

Page 90: Lift off with Groovy 2 at JavaOne 2013

Meta-annotations

@Immutable@ToString(excludes  =  ["age"])@AnnotationCollector@interface  MyAlias  {}

Collected annotations

The collector

57

Page 91: Lift off with Groovy 2 at JavaOne 2013

Meta-annotations

@Immutable@ToString(excludes  =  ["age"])@AnnotationCollector@interface  MyAlias  {}

Collected annotations

The collector

Your own annotation

alias

57

Page 92: Lift off with Groovy 2 at JavaOne 2013

Meta-annotations

@Immutable@ToString(excludes  =  ["age"])@AnnotationCollector@interface  MyAlias  {}

@MyAliasclass  Person  {        String  name        int  age}

Collected annotations

The collector

Your own annotation

alias

57

Page 93: Lift off with Groovy 2 at JavaOne 2013

Meta-annotations

@Immutable@ToString(excludes  =  ["age"])@AnnotationCollector@interface  MyAlias  {}

@MyAliasclass  Person  {        String  name        int  age}

Collected annotations

The collector

Your own annotation

aliasUse your meta-

annotation

57

Page 94: Lift off with Groovy 2 at JavaOne 2013

@DelegatesTo annotation

Richer tooling supportfor Domain-Specific Languages

Page 95: Lift off with Groovy 2 at JavaOne 2013

@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

Page 96: Lift off with Groovy 2 at JavaOne 2013

@DelegatesTo annotation

exec(spec)  {        foo()}

60

Page 97: Lift off with Groovy 2 at JavaOne 2013

@DelegatesTo annotationclass  ExecSpec  {        void  foo()}

exec(spec)  {        foo()}

60

Page 98: Lift off with Groovy 2 at JavaOne 2013

@DelegatesTo annotationclass  ExecSpec  {        void  foo()}

void  exec(ExecSpec  sp,  Closure  c)  {        c.delegate  =  sp        c()}

exec(spec)  {        foo()}

60

Page 99: Lift off with Groovy 2 at JavaOne 2013

@DelegatesTo annotationclass  ExecSpec  {        void  foo()}

void  exec(ExecSpec  sp,  Closure  c)  {        c.delegate  =  sp        c()}

exec(spec)  {        foo()}

The static type checker doesn’t know about method foo()

60

Page 100: Lift off with Groovy 2 at JavaOne 2013

@DelegatesTo annotationclass  ExecSpec  {        void  foo()}

void  exec(ExecSpec  sp,  Closure  c)  {        c.delegate  =  sp        c()}

exec(spec)  {        foo()}

Annotate with @DelegatesTo(ExecSpec)

The static type checker doesn’t know about method foo()

60

Page 101: Lift off with Groovy 2 at JavaOne 2013

@DelegatesTo annotation

• With another delegation strategy

void  exec(ExecSpec  sp,  Closure  c)  {        c.delegate  =  sp        c.resolveStrategy  =  DELEGATE_FIRST        c()}

61

Page 102: Lift off with Groovy 2 at JavaOne 2013

@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

Page 103: Lift off with Groovy 2 at JavaOne 2013

@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

Page 104: Lift off with Groovy 2 at JavaOne 2013

Extend the static type checker

To go even further than Java itself !

Page 105: Lift off with Groovy 2 at JavaOne 2013

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

Page 106: Lift off with Groovy 2 at JavaOne 2013

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

Page 107: Lift off with Groovy 2 at JavaOne 2013

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

Page 108: Lift off with Groovy 2 at JavaOne 2013

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

Page 109: Lift off with Groovy 2 at JavaOne 2013

Extend the static type checker

onMethodSelection  {  expr,  method  -­‐>  ...  }afterMethodCall  {  mc  -­‐>  ...  }unresolvedVariable  {  var  -­‐>  ...  }methodNotFound  {  receiver,  name,  argList,  argTypes,  call  -­‐>  ...  }incompatibleAssignment  {  lhsType,  rhsType,  expr  -­‐>  ...  }

67

Page 110: Lift off with Groovy 2 at JavaOne 2013

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

Page 111: Lift off with Groovy 2 at JavaOne 2013

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

Page 112: Lift off with Groovy 2 at JavaOne 2013

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

Page 113: Lift off with Groovy 2 at JavaOne 2013

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

Page 114: Lift off with Groovy 2 at JavaOne 2013

Compiler configuration

Custom base script classConfiguration script

Configuration DSL

Page 115: Lift off with Groovy 2 at JavaOne 2013

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

Page 116: Lift off with Groovy 2 at JavaOne 2013

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

Page 117: Lift off with Groovy 2 at JavaOne 2013

Compiler customization

• Add the @ToString AST transformation

import  groovy.transform.ToStringimport  org.codehaus.groovy.control.customizers              .ASTTransformationCustomizer

configuration.addCompilationCustomizer(        new  ASTTransformationCustomizer(ToString))

72

Page 118: Lift off with Groovy 2 at JavaOne 2013

Compiler customization

• Add the @ToString AST transformation

import  groovy.transform.ToStringimport  org.codehaus.groovy.control.customizers              .ASTTransformationCustomizer

configuration.addCompilationCustomizer(        new  ASTTransformationCustomizer(ToString))

CompilerConfiguration instance,injected by default

72

Page 119: Lift off with Groovy 2 at JavaOne 2013

Compiler customization

• A small DSL to configure the customization

configuration.customizers  {        //  apply  to  MyBean.groovy        source(basename:  'MyBean')  {                ast(ToString)        }}

73

Page 120: Lift off with Groovy 2 at JavaOne 2013

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

Page 121: Lift off with Groovy 2 at JavaOne 2013

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

Page 122: Lift off with Groovy 2 at JavaOne 2013

To learn more...Groovy 2.0http://groovy.codehaus.org/Groovy+2.0+release+notes

Groovy 2.1http://groovy.codehaus.org/Groovy+2.1+release+notes

Page 123: Lift off with Groovy 2 at JavaOne 2013

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

New « MOP »New Grammar with Antlr v4Java 8 Lambdas support

Page 124: Lift off with Groovy 2 at JavaOne 2013

A few words about the roadmap

2014 2014 20132012

Groovy 2.1

Groovy 2.0Groovy 2.0 Groovy 2.2

Groovy 2.3

76

Groovy 3.0

Page 125: Lift off with Groovy 2 at JavaOne 2013

A few words about the roadmap

2014 2014 20132012

Groovy 2.1

Groovy 2.0Groovy 2.0 Groovy 2.2

Groovy 2.3

76

Groovy 3.0

Page 126: Lift off with Groovy 2 at JavaOne 2013

A few words about the roadmap

2014 2014 20132012

Groovy 2.1

Groovy 2.0Groovy 2.0 Groovy 2.2

Groovy 2.3

76

Groovy 3.0

Page 127: Lift off with Groovy 2 at JavaOne 2013

Groovy 2.2

Implicit closure coercion@Memoized transformation

DelegatingScript base script class

Page 128: Lift off with Groovy 2 at JavaOne 2013

Implicit closure coercion

78

Page 129: Lift off with Groovy 2 at JavaOne 2013

Implicit closure coercion

interface  Predicate<T>  {        boolean  test(T  t)}

List<T>  filter(Predicate<T>  p)

78

Page 130: Lift off with Groovy 2 at JavaOne 2013

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

Page 131: Lift off with Groovy 2 at JavaOne 2013

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

Page 132: Lift off with Groovy 2 at JavaOne 2013

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

Page 133: Lift off with Groovy 2 at JavaOne 2013

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

Page 134: Lift off with Groovy 2 at JavaOne 2013

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

Page 135: Lift off with Groovy 2 at JavaOne 2013

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

Page 136: Lift off with Groovy 2 at JavaOne 2013

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

Page 137: Lift off with Groovy 2 at JavaOne 2013

DelegatingScript base script class

• Special base script class to delegate method calls and property accesses to a delegatee

79

Page 138: Lift off with Groovy 2 at JavaOne 2013

DelegatingScript base script class

• Special base script class to delegate method calls and property accesses to a delegatee

Handy for DSLs!

79

Page 139: Lift off with Groovy 2 at JavaOne 2013

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

Page 140: Lift off with Groovy 2 at JavaOne 2013

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

Page 141: Lift off with Groovy 2 at JavaOne 2013

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

Page 142: Lift off with Groovy 2 at JavaOne 2013

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

Page 143: Lift off with Groovy 2 at JavaOne 2013

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

Page 144: Lift off with Groovy 2 at JavaOne 2013

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

Page 145: Lift off with Groovy 2 at JavaOne 2013

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

Page 146: Lift off with Groovy 2 at JavaOne 2013

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

Page 147: Lift off with Groovy 2 at JavaOne 2013

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

Page 148: Lift off with Groovy 2 at JavaOne 2013

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

Page 149: Lift off with Groovy 2 at JavaOne 2013

groovysh doc command

81

Page 150: Lift off with Groovy 2 at JavaOne 2013

groovysh doc command

Launches your browser with the JavaDoc and GDK doc of the class

81

Page 151: Lift off with Groovy 2 at JavaOne 2013

groovysh code completion

82

Page 152: Lift off with Groovy 2 at JavaOne 2013

groovysh code completion

Import completion

82

Page 153: Lift off with Groovy 2 at JavaOne 2013

groovysh code completion

Import completion

Method call completion

82

Page 154: Lift off with Groovy 2 at JavaOne 2013

@Memoized transformation

• Piggypack on Closure’s own memoization capabilities, but applied to methods

@Memoized  int  expensiveOp(int  a,  int  b)  {        sleep  1000        return  a  +  b}//  one  second  to  returnexpensiveOp(1,  2)  //  immediate  result  returnedexpensiveOp(1,  2)

83

Page 155: Lift off with Groovy 2 at JavaOne 2013

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

Page 156: Lift off with Groovy 2 at JavaOne 2013

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

Page 157: Lift off with Groovy 2 at JavaOne 2013

Likely inGroovy 2.3

TraitsGroovyDoc rewrite

New documentation & website

Page 158: Lift off with Groovy 2 at JavaOne 2013

Trait implementation

87

Page 159: Lift off with Groovy 2 at JavaOne 2013

Trait implementation

trait  FlyingAbility  {        String  fly()  {                "I  believe  I  can  fly!"        }}

87

Page 160: Lift off with Groovy 2 at JavaOne 2013

Trait implementation

trait  FlyingAbility  {        String  fly()  {                "I  believe  I  can  fly!"        }}

A trait keyword applying the @Trait transformation

87

Page 161: Lift off with Groovy 2 at JavaOne 2013

Trait implementation

trait  FlyingAbility  {        String  fly()  {                "I  believe  I  can  fly!"        }}

A trait keyword applying the @Trait transformation

class  Car  implements  FlyingAbility  {}

87

Page 162: Lift off with Groovy 2 at JavaOne 2013

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

Page 163: Lift off with Groovy 2 at JavaOne 2013

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

Page 164: Lift off with Groovy 2 at JavaOne 2013

GroovyDoc rewrite

88

Page 165: Lift off with Groovy 2 at JavaOne 2013

GroovyDoc rewrite

GroovyDoc != Sexy Doc

88

Page 166: Lift off with Groovy 2 at JavaOne 2013

New documentation and website

• New reference documentation and guides using AsciiDoctor

• New website with a refreshed skin and the new content

89

Page 167: Lift off with Groovy 2 at JavaOne 2013

Groovy 3

New MOPNew Antlr v4 grammarJDK 8 lambda support

Page 168: Lift off with Groovy 2 at JavaOne 2013

MOP

2

Page 169: Lift off with Groovy 2 at JavaOne 2013

Antlr 4grammar

Page 170: Lift off with Groovy 2 at JavaOne 2013

λJDK

8

Page 171: Lift off with Groovy 2 at JavaOne 2013
Page 172: Lift off with Groovy 2 at JavaOne 2013

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

Page 173: Lift off with Groovy 2 at JavaOne 2013

Summary

•Groovy 2.1– Invoke Dynamic support completed– @DelegatesTo annotation– type checker extensions for DSLs– meta-annotations

96

Page 174: Lift off with Groovy 2 at JavaOne 2013

Summary

• Groovy 2.2 – implicit closure coercion– @Memoized transformation– DelegatingScript for script DSLs– groovysh improvements

97

Page 175: Lift off with Groovy 2 at JavaOne 2013

Summary

• Groovy 2.3– traits– new GroovyDoc– new documentation– new website

98

Page 176: Lift off with Groovy 2 at JavaOne 2013

Summary

• Groovy 3– a new MOP (Meta-Object Protocol)– a new grammar with Antlr v4– the support of JDK 8 and lambdas

99

Page 177: Lift off with Groovy 2 at JavaOne 2013

Questions & Answers

Page 178: Lift off with Groovy 2 at JavaOne 2013

Thank you! @glaforge

http://glaforge.appspot.com

http://gplus.to/glaforge

Page 179: Lift off with Groovy 2 at JavaOne 2013

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