SlideShare ist ein Scribd-Unternehmen logo
1 von 445
Downloaden Sie, um offline zu lesen
Groovy, Reactor, Grails 

& the realtime web
Guillaume Laforge 

@glaforge !

Stéphane Maldini

@smaldini !
Stéphane
Maldini
Consultant and Reactor committer
at
.
!

@smaldini
Guillaume
Laforge
Groovy project lead
at
.
!

@glaforge
http://glaforge.appspot.com
Les Cast
Codeurs
0
t
r
a
P

Introduction
Valuable users
don’t like to wait
Realtime web
applications are about
the « now »
Show users live
updates as they come
Show users live
updates as they come

A « push » approach vs a
« pull » approach
Show users live
updates as they come

A « push » approach vs a
« pull » approach
Handle a big
volume of events
Show users live
updates as they come

A « push » approach vs a
« pull » approach
Handle a big
volume of events

React fast to
new events
Show users live
updates as they come

A « push » approach vs a
« pull » approach
Handle a big
volume of events

React fast to
new events

Use promises, events,
streams to react fast and
stream updates to users as
they are ready
Show users live
updates as they come
Avoid blocking
and state

A « push » approach vs a
« pull » approach
Handle a big
volume of events

React fast to
new events

Use promises, events,
streams to react fast and
stream updates to users as
they are ready
Show users live
updates as they come

Fail gracefully

Avoid blocking
and state

A « push » approach vs a
« pull » approach
Handle a big
volume of events

React fast to
new events

Use promises, events,
streams to react fast and
stream updates to users as
they are ready
Sharp tools:
Groovy, Reactor &
Grails
1
t
r
a
P

Groovy
Groovy…
an Open Source 

alternative language 

for the JVM
Groovy…
Object-oriented, dynamic,
with a functional flavor
Groovy…
But also supports 

static type checking & 

static compilation
1.7

million 

downloads

per year
Yup, we’re all
using Groovy!
Simplify the life of
(Java) developers
Groovy as a Java
superset
Groovy as a Java
superset

It’s so easy to
learn!
As safe and fast as Java with
static type checking & compilation
As safe and fast as Java with
static type checking & compilation
new	
  MarkupBuilder().html	
  {	
  
	
  	
  	
  	
  head	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  title	
  "The	
  Script	
  Bowl"	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  body	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  div(class:	
  "banner")	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  p	
  "Groovy	
  rocks!"	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
}
move	
  forward	
  at	
  3.km/h
Expressive,
Concise,
Readable
Speaking of conciseness...
A full Spring app in the span of a tweet!
@RestController	
  
class	
  App	
  {	
  
	
  	
  	
  	
  @RequestMapping("/")	
  
	
  	
  	
  	
  String	
  home()	
  {	
  "Hello	
  World!"	
  }	
  
}
Great for
scripting
Great for
scripting

Fit for Domain-Specific
Languages
Great for
scripting

Fit for Domain-Specific
Languages

Most seamless integration &
interoperability wih java!
Great for
scripting

Full-blown reactive
applications too!

Fit for Domain-Specific
Languages

Most seamless integration &
interoperability wih java!
Most Java code is also
valid Groovy code!
Most Java code is also
valid Groovy code!

Any Java developer is a
Groovy developer!
Flat learning
curve
Flat learning
curve

Easy to learn
Scripts versus Classes
public	
  class	
  Main	
  {	
  
	
  	
  	
  	
  public	
  static	
  void	
  main(String[]	
  args)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  System.out.println("Hello");	
  
	
  	
  	
  	
  }	
  
}

vs
@glaforge — @smaldini / #DV13-rtweb

!26
Scripts versus Classes
public	
  class	
  Main	
  {	
  
	
  	
  	
  	
  public	
  static	
  void	
  main(String[]	
  args)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  System.out.println("Hello");	
  
	
  	
  	
  	
  }	
  
}

vs
println	
  "Hello"
@glaforge — @smaldini / #DV13-rtweb

!26
Optional
Semicolons

Optional
Semicolons

Optional

Parentheses
Semicolons

Optional
return keyword

Parentheses
Semicolons

Parentheses

Optional
return keyword

public keyword
Semicolons

Optional
return keyword

Parentheses

Typing!

public keyword
Optional...
public	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner;	
  
!

	
  	
  	
  	
  public	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  owner;	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  public	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner;	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  public	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner;	
  
	
  	
  	
  	
  }	
  
}	
  
!

Greeter	
  greeter	
  =	
  new	
  Greeter();	
  
greeter.setOwner("Guillaume");	
  
!

System.out.println(greeter.greet("Marion"));

@glaforge — @smaldini / #DV13-rtweb

!28
Optional...

Semicolons

public	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner;	
  
!

	
  	
  	
  	
  public	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  owner;	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  public	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner;	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  public	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner;	
  
	
  	
  	
  	
  }	
  
}	
  
!

Greeter	
  greeter	
  =	
  new	
  Greeter();	
  
greeter.setOwner("Guillaume");	
  
!

System.out.println(greeter.greet("Marion"));

@glaforge — @smaldini / #DV13-rtweb

!28
Optional...
public	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner	
  
!

	
  	
  	
  	
  public	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  owner	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  public	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  public	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!

Greeter	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner("Guillaume")	
  
!

System.out.println(greeter.greet("Marion"))

@glaforge — @smaldini / #DV13-rtweb

!29
Optional...
public	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner	
  
!

	
  	
  	
  	
  public	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  owner	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  public	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  public	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!

Greeter	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner("Guillaume")	
  
!

System.out.println(greeter.greet("Marion"))

@glaforge — @smaldini / #DV13-rtweb

!30
Optional...
public	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner	
  
!

	
  	
  	
  	
  public	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  owner	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  public	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  public	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!

Greeter	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner("Guillaume")	
  

Parentheses

!

System.out.println(greeter.greet("Marion"))

@glaforge — @smaldini / #DV13-rtweb

!30
Optional...
public	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner	
  
!

	
  	
  	
  	
  public	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  owner	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  public	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  public	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!

Greeter	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner	
  "Guillaume"	
  
!

System.out.println	
  greeter.greet("Marion")

@glaforge — @smaldini / #DV13-rtweb

!31
Optional...
public	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner	
  
!

	
  	
  	
  	
  public	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  owner	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  public	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner	
  
	
  	
  	
  	
  }	
  
!

return keyword

	
  	
  	
  	
  public	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!

Greeter	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner	
  "Guillaume"	
  
!

System.out.println	
  greeter.greet("Marion")

@glaforge — @smaldini / #DV13-rtweb

!31
Optional...
public	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner	
  
!

	
  	
  	
  	
  public	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  owner	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  public	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  public	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!

Greeter	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner	
  "Guillaume"	
  
!

System.out.println	
  greeter.greet("Marion")

@glaforge — @smaldini / #DV13-rtweb

!32
Optional...
public	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner	
  
!

	
  	
  	
  	
  public	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  owner	
  
	
  	
  	
  	
  }	
  
!

public keyword

	
  	
  	
  	
  public	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  public	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!

Greeter	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner	
  "Guillaume"	
  
!

System.out.println	
  greeter.greet("Marion")

@glaforge — @smaldini / #DV13-rtweb

!32
Optional...
	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  owner	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!

Greeter	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner	
  "Guillaume"	
  
!

System.out.println	
  greeter.greet("Marion")

@glaforge — @smaldini / #DV13-rtweb

!33
Optional...
	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  owner	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  

optional typing

!

Greeter	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner	
  "Guillaume"	
  
!

System.out.println	
  greeter.greet("Marion")

@glaforge — @smaldini / #DV13-rtweb

!33
Optional...
	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  owner	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!

def	
  	
  	
  	
  	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner	
  "Guillaume"	
  
!

System.out.println	
  greeter.greet("Marion")

@glaforge — @smaldini / #DV13-rtweb

!34
Optional...
	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  owner	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  

handy println shortcut
def	
  	
  	
  	
  	
  greeter	
  =	
  new	
  Greeter()	
  
!

greeter.setOwner	
  "Guillaume"	
  
!

System.out.println	
  greeter.greet("Marion")

@glaforge — @smaldini / #DV13-rtweb

!34
Optional...
	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  owner	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!

def	
  	
  	
  	
  	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner	
  "Guillaume"	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  println	
  greeter.greet("Marion")

@glaforge — @smaldini / #DV13-rtweb

!35
Optional...

verbose Java properties!

	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  getOwner()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  owner	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!

def	
  	
  	
  	
  	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner	
  "Guillaume"	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  println	
  greeter.greet("Marion")

@glaforge — @smaldini / #DV13-rtweb

!35
Optional...
	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  owner	
  
!
!
!
!
!
!
!
!
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!

def	
  	
  	
  	
  	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner	
  "Guillaume"	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  println	
  greeter.greet("Marion")

@glaforge — @smaldini / #DV13-rtweb

!36
Optional...
	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  owner	
  
!
!
!
!
!
!
!
!
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!

Property notation

def	
  	
  	
  	
  	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.setOwner	
  "Guillaume"	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  println	
  greeter.greet("Marion")

@glaforge — @smaldini / #DV13-rtweb

!36
Optional...
	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  owner	
  
!
!
!
!
!
!
!
!
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!

def	
  	
  	
  	
  	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.owner	
  =	
  	
  "Guillaume"	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  println	
  greeter.greet("Marion")

@glaforge — @smaldini / #DV13-rtweb

!37
Optional...
	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  owner	
  
!
!
!
!
!
!
!
!

Named argument
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
constructor
!

	
  	
  	
  	
  }	
  
}	
  
!

def	
  	
  	
  	
  	
  greeter	
  =	
  new	
  Greeter()	
  
greeter.owner	
  =	
  	
  "Guillaume"	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  println	
  greeter.greet("Marion")

@glaforge — @smaldini / #DV13-rtweb

!37
Optional...
	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  owner	
  
!
!
!
!
!
!
!
!
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!

def	
  	
  	
  	
  	
  greeter	
  =	
  new	
  Greeter(owner:	
  "Guillaume")	
  
!
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  println	
  greeter.greet("Marion")

@glaforge — @smaldini / #DV13-rtweb

!38
Optional...
	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  owner	
  
!
!
!
!
!
!

Interpolated strings!
(aka GStrings)

!
!
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner	
  
	
  	
  	
  	
  }	
  
}	
  
!

def	
  	
  	
  	
  	
  greeter	
  =	
  new	
  Greeter(owner:	
  "Guillaume")	
  
!
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  println	
  greeter.greet("Marion")

@glaforge — @smaldini / #DV13-rtweb

!38
Optional...
	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  owner	
  
!
!
!
!
!
!
!
!
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  ${name},	
  I	
  am	
  ${owner}"	
  
	
  	
  	
  	
  }	
  
}	
  
!

def	
  	
  	
  	
  	
  greeter	
  =	
  new	
  Greeter(owner:	
  "Guillaume")	
  
!
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  println	
  greeter.greet("Marion")

@glaforge — @smaldini / #DV13-rtweb

!39
Optional...
	
  	
  	
  	
  	
  	
  	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  owner	
  
!
!
!
!

Let’s reformat that mess
of whitespace!

!
!
!
!
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Hello	
  ${name},	
  I	
  am	
  ${owner}"	
  
	
  	
  	
  	
  }	
  
}	
  
!

def	
  	
  	
  	
  	
  greeter	
  =	
  new	
  Greeter(owner:	
  "Guillaume")	
  
!
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  println	
  greeter.greet("Marion")

@glaforge — @smaldini / #DV13-rtweb

!39
Optional...
class	
  Greeter	
  {	
  
	
  	
  	
  	
  String	
  owner	
  
!

	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  "Hello	
  ${name},	
  I	
  am	
  ${owner}"	
  
	
  	
  	
  	
  }	
  
}	
  
!

def	
  greeter	
  =	
  new	
  Greeter(owner:	
  "Guillaume")	
  
!

println	
  greeter.greet("Marion")

@glaforge — @smaldini / #DV13-rtweb

!40
Optional...
public	
  class	
  Greeter	
  {	
  
	
  	
  	
  	
  private	
  String	
  owner;	
  
!

	
  	
  	
  	
  public	
  String	
  getOwner()	
  {	
  
class	
  Greeter	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  owner;	
  
	
  	
  	
  	
  String	
  owner	
  
	
  	
  	
  	
  }	
  
!
!

	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  public	
  void	
  setOwner(String	
  owner)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  "Hello	
  ${name},	
  I	
  am	
  ${owner}"	
  
	
  	
  	
  	
  	
  	
  	
  	
  this.owner	
  =	
  owner;	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
}	
  
!

!

	
  	
  	
  	
  public	
  String	
  greet(String	
  name)	
  {	
  
def	
  greeter	
  =	
  new	
  Greeter(owner:	
  "Guillaume")	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  "Hello	
  "	
  +	
  name	
  +	
  ",	
  I	
  am	
  "	
  +	
  owner;	
  
!
	
  	
  	
  	
  }	
  
println	
  greeter.greet("Marion")
}	
  
!

Greeter	
  greeter	
  =	
  new	
  Greeter();	
  
greeter.setOwner("Guillaume");	
  
!

System.out.println(greeter.greet("Marion"));

@glaforge — @smaldini / #DV13-rtweb

!40
Optional...
class	
  Greeter	
  {	
  
	
  	
  	
  	
  String	
  owner	
  
!

	
  	
  	
  	
  String	
  greet(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  "Hello	
  ${name},	
  I	
  am	
  ${owner}"	
  
	
  	
  	
  	
  }	
  
}	
  
!

def	
  greeter	
  =	
  new	
  Greeter(owner:	
  "Guillaume")	
  
!

println	
  greeter.greet("Marion")

@glaforge — @smaldini / #DV13-rtweb

!40
Native syntax constructs
//	
  closures	
  
def	
  adder	
  =	
  {	
  a,	
  b	
  -­‐>	
  a	
  +	
  b	
  }	
  
!

//	
  lists	
  
def	
  list	
  =	
  [1,	
  2,	
  3,	
  4,	
  5]	
  
!

//	
  maps	
  
def	
  map	
  =	
  [a:	
  1,	
  b:	
  2,	
  c:	
  3]	
  
!

//	
  regular	
  expressions	
  
def	
  regex	
  =	
  ~/.*foo.*/	
  
!

//	
  ranges	
  
def	
  range	
  128..255
@glaforge — @smaldini / #DV13-rtweb

!41
Closures — the basics
• Functions as first-class citizen of the language

def	
  adder	
  =	
  {	
  a,	
  b	
  -­‐>	
  a	
  +	
  b	
  }	
  
!

assert	
  adder(1,	
  2)	
  ==	
  3	
  
assert	
  adder('a',	
  'b')	
  ==	
  'ab'

@glaforge — @smaldini / #DV13-rtweb

!42
Closures — the basics
• Functions as first-class citizen of the language
Closure
parameters

def	
  adder	
  =	
  {	
  a,	
  b	
  -­‐>	
  a	
  +	
  b	
  }	
  
!

assert	
  adder(1,	
  2)	
  ==	
  3	
  
assert	
  adder('a',	
  'b')	
  ==	
  'ab'

@glaforge — @smaldini / #DV13-rtweb

!42
Closures — the basics
• Functions as first-class citizen of the language
Assign a function
Closure
into a variable
parameters

def	
  adder	
  =	
  {	
  a,	
  b	
  -­‐>	
  a	
  +	
  b	
  }	
  
!

assert	
  adder(1,	
  2)	
  ==	
  3	
  
assert	
  adder('a',	
  'b')	
  ==	
  'ab'

@glaforge — @smaldini / #DV13-rtweb

!42
Closures — the basics
• Functions as first-class citizen of the language
Assign a function
Closure
into a variable
parameters

def	
  adder	
  =	
  {	
  a,	
  b	
  -­‐>	
  a	
  +	
  b	
  }	
  
!

assert	
  adder(1,	
  2)	
  ==	
  3	
  
assert	
  adder('a',	
  'b')	
  ==	
  'ab'
Short form of:
adder.call(‘a’, ‘b’)
@glaforge — @smaldini / #DV13-rtweb

!42
Closures — the basics
• Functions as first-class citizen of the language
Assign a function
Closure
into a variable
parameters

def	
  adder	
  =	
  {	
  a,	
  b	
  -­‐>	
  a	
  +	
  b	
  }	
  
!

assert	
  adder(1,	
  2)	
  ==	
  3	
  
assert	
  adder('a',	
  'b')	
  ==	
  'ab'
Short form of:
adder.call(‘a’, ‘b’)
@glaforge — @smaldini / #DV13-rtweb

Genericity with
duck typing & operator
overloading
!42
Closures — explicit type

!

def	
  intAdder	
  =	
  {	
  int	
  a,	
  int	
  b	
  -­‐>	
  a	
  +	
  b	
  }

@glaforge — @smaldini / #DV13-rtweb

!43
Closures — explicit type
Be explicit about
the types
!

def	
  intAdder	
  =	
  {	
  int	
  a,	
  int	
  b	
  -­‐>	
  a	
  +	
  b	
  }

@glaforge — @smaldini / #DV13-rtweb

!43
Closures — implicit parameter

def	
  doubler	
  =	
  {	
  it	
  *	
  2	
  }	
  
!

assert	
  doubler(3)	
  ==	
  6	
  
assert	
  doubler('a')	
  ==	
  'aa'

@glaforge — @smaldini / #DV13-rtweb

!44
Closures — implicit parameter
Implicit
parameter

def	
  doubler	
  =	
  {	
  it	
  *	
  2	
  }	
  
!

assert	
  doubler(3)	
  ==	
  6	
  
assert	
  doubler('a')	
  ==	
  'aa'

@glaforge — @smaldini / #DV13-rtweb

!44
Closures — implicit parameter
Implicit
parameter

def	
  doubler	
  =	
  {	
  it	
  *	
  2	
  }	
  
!

assert	
  doubler(3)	
  ==	
  6	
  
assert	
  doubler('a')	
  ==	
  'aa'
Multiply also defined
on strings
@glaforge — @smaldini / #DV13-rtweb

!44
Closures — variable arguments

def	
  sum	
  =	
  {	
  ...	
  elements	
  -­‐>	
  

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  elements.sum()	
  }	
  
!

assert	
  sum(1,	
  2)	
  ==	
  3	
  
assert	
  sum('a',	
  'b',	
  'c')	
  ==	
  'abc'

@glaforge — @smaldini / #DV13-rtweb

!45
Closures — variable arguments
Variable number of
arguments

def	
  sum	
  =	
  {	
  ...	
  elements	
  -­‐>	
  

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  elements.sum()	
  }	
  
!

assert	
  sum(1,	
  2)	
  ==	
  3	
  
assert	
  sum('a',	
  'b',	
  'c')	
  ==	
  'abc'

@glaforge — @smaldini / #DV13-rtweb

!45
Closures — variable arguments
You can specify the
type: int...

Variable number of
arguments

def	
  sum	
  =	
  {	
  ...	
  elements	
  -­‐>	
  

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  elements.sum()	
  }	
  
!

assert	
  sum(1,	
  2)	
  ==	
  3	
  
assert	
  sum('a',	
  'b',	
  'c')	
  ==	
  'abc'

@glaforge — @smaldini / #DV13-rtweb

!45
Closures — default values

def	
  mult	
  =	
  {	
  int	
  a,	
  int	
  b	
  =	
  10	
  -­‐>	
  a	
  *	
  b	
  }	
  
!

assert	
  mult(2,	
  3)	
  ==	
  6	
  
assert	
  mult(5)	
  ==	
  50

@glaforge — @smaldini / #DV13-rtweb

!46
Closures — default values
Default value
def	
  mult	
  =	
  {	
  int	
  a,	
  int	
  b	
  =	
  10	
  -­‐>	
  a	
  *	
  b	
  }	
  
!

assert	
  mult(2,	
  3)	
  ==	
  6	
  
assert	
  mult(5)	
  ==	
  50

@glaforge — @smaldini / #DV13-rtweb

!46
Closures — default values
Default value
def	
  mult	
  =	
  {	
  int	
  a,	
  int	
  b	
  =	
  10	
  -­‐>	
  a	
  *	
  b	
  }	
  
!

assert	
  mult(2,	
  3)	
  ==	
  6	
  
assert	
  mult(5)	
  ==	
  50

@glaforge — @smaldini / #DV13-rtweb

Provided value
for b

!46
Closures — default values
Default value
def	
  mult	
  =	
  {	
  int	
  a,	
  int	
  b	
  =	
  10	
  -­‐>	
  a	
  *	
  b	
  }	
  
!

assert	
  mult(2,	
  3)	
  ==	
  6	
  
assert	
  mult(5)	
  ==	
  50

Default value
used for b
@glaforge — @smaldini / #DV13-rtweb

Provided value
for b

!46
Closures — methods as functions

def	
  logBase10	
  =	
  Math.&log10	
  
def	
  printer	
  =	
  System.out.&println	
  
!

assert	
  logBase10(10)	
  ==	
  1	
  
printer	
  'abc'

@glaforge — @smaldini / #DV13-rtweb

!47
Closures — methods as functions
Turn a method into a closure function

def	
  logBase10	
  =	
  Math.&log10	
  
def	
  printer	
  =	
  System.out.&println	
  
!

assert	
  logBase10(10)	
  ==	
  1	
  
printer	
  'abc'

@glaforge — @smaldini / #DV13-rtweb

!47
Closures — map / filter / reduce

@glaforge — @smaldini / #DV13-rtweb

!48
Closures — map / filter / reduce
@groovy.transform.Immutable

class	
  Person	
  {

	
  	
  	
  	
  String	
  name

	
  	
  	
  	
  int	
  age

}

@glaforge — @smaldini / #DV13-rtweb

!48
Closures — map / filter / reduce
@groovy.transform.Immutable

class	
  Person	
  {

	
  	
  	
  	
  String	
  name

	
  	
  	
  	
  int	
  age

}

@glaforge — @smaldini / #DV13-rtweb

!48
Closures — map / filter / reduce
@groovy.transform.Immutable

class	
  Person	
  {

	
  	
  	
  	
  String	
  name

	
  	
  	
  	
  int	
  age

}
def	
  persons	
  =	
  [

	
  	
  	
  	
  new	
  Person('Guillaume',	
  36),

	
  	
  	
  	
  new	
  Person('Marion',	
  5),

	
  	
  	
  	
  new	
  Person('Erine',	
  1)

]

@glaforge — @smaldini / #DV13-rtweb

!48
Closures — map / filter / reduce
@groovy.transform.Immutable

class	
  Person	
  {

	
  	
  	
  	
  String	
  name

	
  	
  	
  	
  int	
  age

}
def	
  persons	
  =	
  [

	
  	
  	
  	
  new	
  Person('Guillaume',	
  36),

	
  	
  	
  	
  new	
  Person('Marion',	
  5),

	
  	
  	
  	
  new	
  Person('Erine',	
  1)

]

@glaforge — @smaldini / #DV13-rtweb

!48
Closures — map / filter / reduce
@groovy.transform.Immutable

class	
  Person	
  {

	
  	
  	
  	
  String	
  name

	
  	
  	
  	
  int	
  age

}
def	
  persons	
  =	
  [

	
  	
  	
  	
  new	
  Person('Guillaume',	
  36),

	
  	
  	
  	
  new	
  Person('Marion',	
  5),

	
  	
  	
  	
  new	
  Person('Erine',	
  1)

]
def	
  names	
  =

	
  	
  	
  	
  persons.findAll	
  {	
  it.age	
  <	
  18	
  }

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .collect	
  {	
  it.name.toUpperCase()	
  }

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .sort()

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .join(',	
  ')

@glaforge — @smaldini / #DV13-rtweb

!48
Closures — map / filter / reduce
@groovy.transform.Immutable

class	
  Person	
  {

	
  	
  	
  	
  String	
  name

	
  	
  	
  	
  int	
  age

}
def	
  persons	
  =	
  [

	
  	
  	
  	
  new	
  Person('Guillaume',	
  36),

	
  	
  	
  	
  new	
  Person('Marion',	
  5),

	
  	
  	
  	
  new	
  Person('Erine',	
  1)

]
def	
  names	
  =

	
  	
  	
  	
  persons.findAll	
  {	
  it.age	
  <	
  18	
  }

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .collect	
  {	
  it.name.toUpperCase()	
  }

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .sort()

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .join(',	
  ')

@glaforge — @smaldini / #DV13-rtweb

!48
Closures — map / filter / reduce
@groovy.transform.Immutable

class	
  Person	
  {

	
  	
  	
  	
  String	
  name

	
  	
  	
  	
  int	
  age

}
def	
  persons	
  =	
  [

	
  	
  	
  	
  new	
  Person('Guillaume',	
  36),

	
  	
  	
  	
  new	
  Person('Marion',	
  5),

	
  	
  	
  	
  new	
  Person('Erine',	
  1)

]
def	
  names	
  =

	
  	
  	
  	
  persons.findAll	
  {	
  it.age	
  <	
  18	
  }

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .collect	
  {	
  it.name.toUpperCase()	
  }

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .sort()

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .join(',	
  ')
assert	
  names	
  ==	
  "ERINE,	
  MARION"
@glaforge — @smaldini / #DV13-rtweb

!48
Closures — map / filter / reduce
@groovy.transform.Immutable

class	
  Person	
  {

	
  	
  	
  	
  String	
  name

	
  	
  	
  	
  int	
  age

}
def	
  persons	
  =	
  [

	
  	
  	
  	
  new	
  Person('Guillaume',	
  36),

	
  	
  	
  	
  new	
  Person('Marion',	
  5),

	
  	
  	
  	
  new	
  Person('Erine',	
  1)

]

find/findAll, inject, collect, flatten,
min/max, unique, reverse, collate,
groupBy, any/every, head/tail/last,
count/countBy, combinations/
permutations/subsequences/
transpose, withDefault/
withLazyDefault

def	
  names	
  =

	
  	
  	
  	
  persons.findAll	
  {	
  it.age	
  <	
  18	
  }

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .collect	
  {	
  it.name.toUpperCase()	
  }

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .sort()

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .join(',	
  ')
assert	
  names	
  ==	
  "ERINE,	
  MARION"
@glaforge — @smaldini / #DV13-rtweb

!48
Closures — resource handling

new	
  File('bible.txt').withReader	
  {	
  r	
  -­‐>	
  
	
  	
  	
  	
  new	
  File('out.txt').withWriter	
  {	
  w	
  -­‐>	
  
	
  	
  	
  	
  	
  	
  	
  	
  r.eachLine	
  {	
  line	
  -­‐>	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (line.contains('Groovy'))	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  w	
  <<	
  line.toUpperCase()	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
}

@glaforge — @smaldini / #DV13-rtweb

!49
Closures — resource handling
Take care of properly opening /
closing resources
new	
  File('bible.txt').withReader	
  {	
  r	
  -­‐>	
  
	
  	
  	
  	
  new	
  File('out.txt').withWriter	
  {	
  w	
  -­‐>	
  
	
  	
  	
  	
  	
  	
  	
  	
  r.eachLine	
  {	
  line	
  -­‐>	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (line.contains('Groovy'))	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  w	
  <<	
  line.toUpperCase()	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
}

@glaforge — @smaldini / #DV13-rtweb

!49
Closures — custom control structures

void	
  unless(boolean	
  cond,	
  Closure	
  c)	
  {	
  
	
  	
  	
  	
  if	
  (!cond)	
  c()	
  
}	
  
!

unless	
  (10	
  <	
  9)	
  {	
  
	
  	
  	
  	
  println	
  "less"	
  
}

@glaforge — @smaldini / #DV13-rtweb

!50
Closures — custom control structures
Closure as last argument
void	
  unless(boolean	
  cond,	
  Closure	
  c)	
  {	
  
	
  	
  	
  	
  if	
  (!cond)	
  c()	
  
}	
  
!

unless	
  (10	
  <	
  9)	
  {	
  
	
  	
  	
  	
  println	
  "less"	
  
}

@glaforge — @smaldini / #DV13-rtweb

!50
Closures — custom control structures
Closure as last argument
void	
  unless(boolean	
  cond,	
  Closure	
  c)	
  {	
  
	
  	
  	
  	
  if	
  (!cond)	
  c()	
  
}	
  
!

unless	
  (10	
  <	
  9)	
  {	
  
	
  	
  	
  	
  println	
  "less"	
  
}

@glaforge — @smaldini / #DV13-rtweb

Equivalent to:
unless(10<9, {...})

!50
Closures — custom control structures

class	
  Reactor	
  {	
  	
  
	
  	
  	
  	
  void	
  on(Selector	
  s,	
  Closure	
  c)	
  {	
  …	
  }	
  
}	
  
…	
  
reactor.on(	
  $(‘abc')	
  )	
  {	
  Event<String>	
  ev	
  -­‐>	
  
	
  	
  	
  	
  …	
  
}

@glaforge — @smaldini / #DV13-rtweb

!51
Closures — builders leverage closures
import	
  groovy.json.*	
  
!

def	
  json	
  =	
  new	
  JsonBuilder()	
  
json.person	
  {	
  
	
  	
  	
  	
  name	
  'Guillaume'	
  
	
  	
  	
  	
  age	
  36	
  
	
  	
  	
  	
  daughters	
  'Marion',	
  'Erine'	
  
	
  	
  	
  	
  address	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  street	
  '1	
  Main	
  Street'	
  
	
  	
  	
  	
  	
  	
  	
  	
  zip	
  75001	
  
	
  	
  	
  	
  	
  	
  	
  	
  city	
  'Paris'	
  
	
  	
  	
  	
  }	
  
}
@glaforge — @smaldini / #DV13-rtweb

!52
Closures — builders leverage closures
import	
  groovy.json.*	
  
!

def	
  json	
  =	
  new	
  JsonBuilder()	
  
json.person	
  {	
  
	
  	
  	
  	
  name	
  'Guillaume'	
  
	
  	
  	
  	
  age	
  36	
  
	
  	
  	
  	
  daughters	
  'Marion',	
  'Erine'	
  
	
  	
  	
  	
  address	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  street	
  '1	
  Main	
  Street'	
  
	
  	
  	
  	
  	
  	
  	
  	
  zip	
  75001	
  
	
  	
  	
  	
  	
  	
  	
  	
  city	
  'Paris'	
  
	
  	
  	
  	
  }	
  
}
@glaforge — @smaldini / #DV13-rtweb

Hierarchical data
representation

!52
Closures — builders leverage closures
import	
  groovy.json.*	
  
!

Hierarchical data
representation

def	
  json	
  =	
  new	
  JsonBuilder()	
  
json.person	
  {	
  
	
  	
  	
  	
  name	
  'Guillaume'	
  
	
  	
  	
  	
  age	
  36	
  
Closure blocks
	
  	
  	
  	
  daughters	
  'Marion',	
  'Erine'	
  
delimiting the
	
  	
  	
  	
  address	
  {	
  
structure
	
  	
  	
  	
  	
  	
  	
  	
  street	
  '1	
  Main	
  Street'	
  
	
  	
  	
  	
  	
  	
  	
  	
  zip	
  75001	
  
	
  	
  	
  	
  	
  	
  	
  	
  city	
  'Paris'	
  
	
  	
  	
  	
  }	
  
}
@glaforge — @smaldini / #DV13-rtweb

!52
Closures — builders leverage closures
import	
  groovy.json.*	
  
{	
  
	
  	
  	
  	
  "person":	
  {	
  
Hierarchical data
def	
  json	
  =	
  new	
  JsonBuilder()	
  
	
  	
  	
  	
  	
  	
  	
  	
  "name":	
  "Guillaume",	
  
representation
	
  	
  	
  	
  	
  	
  	
  	
  "age":	
  36,	
  
json.person	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  "daughters":	
  [	
  
	
  	
  	
  	
  name	
  'Guillaume'	
   	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Marion",	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "Erine"	
  
	
  	
  	
  	
  age	
  36	
  
	
  	
  	
  	
  	
  	
  	
  	
  ],	
  
Closure blocks
	
  	
  	
  	
  daughters	
  'Marion',	
  'Erine'	
  
	
  	
  	
  	
  	
  	
  	
  	
  "address":	
  {	
  
delimiting the
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "street":	
  "1	
  Main	
  Street",	
  
	
  	
  	
  	
  address	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "zip":	
  75001,	
  
structure
	
  	
  	
  	
  	
  	
  	
  	
  street	
  '1	
  Main	
  Street'	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "city":	
  "Paris"	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  zip	
  75001	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  city	
  'Paris'	
   }
!

	
  	
  	
  	
  }	
  
}
@glaforge — @smaldini / #DV13-rtweb

!52
Closure — your own builders
GroovyEnvironment.create	
  {	
  
	
  	
  	
  	
  environment	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  defaultDispatcher	
  =	
  "test"	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  dispatcher('test')	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  type	
  =	
  DispatcherType.SYNCHRONOUS	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
}

@glaforge — @smaldini / #DV13-rtweb

!53
Closure — your own builders
GroovyEnvironment.create	
  {	
  
	
  	
  	
  	
  environment	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  defaultDispatcher	
  =	
  "test"	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  dispatcher('test')	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  type	
  =	
  DispatcherType.SYNCHRONOUS	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
}

@glaforge — @smaldini / #DV13-rtweb

!53
Closure — your own builders
GroovyEnvironment.create	
  {	
  
	
  	
  	
  	
  environment	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  defaultDispatcher	
  =	
  "test"	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  dispatcher('test')	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  type	
  =	
  DispatcherType.SYNCHRONOUS	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
}

@glaforge — @smaldini / #DV13-rtweb

!53
Closure — your own builders
GroovyEnvironment.create	
  {	
  
	
  	
  	
  	
  environment	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  defaultDispatcher	
  =	
  "test"	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  dispatcher('test')	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  type	
  =	
  DispatcherType.SYNCHRONOUS	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
}

@glaforge — @smaldini / #DV13-rtweb

!53
Closure — your own builders
GroovyEnvironment.create	
  {	
  
	
  	
  	
  	
  environment	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  defaultDispatcher	
  =	
  "test"	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  dispatcher('test')	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  type	
  =	
  DispatcherType.SYNCHRONOUS	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
}

@glaforge — @smaldini / #DV13-rtweb

!53
Closure — your own builders
Implement a builder extending
BuilderSupport or FactoryBuilderSupport…
GroovyEnvironment.create	
  {	
  
or roll your own!
	
  	
  	
  	
  environment	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  defaultDispatcher	
  =	
  "test"	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  dispatcher('test')	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  type	
  =	
  DispatcherType.SYNCHRONOUS	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
}

@glaforge — @smaldini / #DV13-rtweb

!53
Closure — your own builders
Implement a builder extending
BuilderSupport or FactoryBuilderSupport…
GroovyEnvironment.create	
  {	
  
or roll your own!

	
  	
  	
  	
  environment	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  defaultDispatcher	
  =	
  "test"	
  
abstract	
  class	
  BuilderSupport	
  {	
  

	
  	
  	
  	
  abstract	
  void	
  setParent(Object	
  parent,	
  Object	
  child)	
  
!
	
  	
  	
  	
  abstract	
  Object	
  createNode(Object	
  name)	
  
	
  	
  	
  	
  	
  	
  	
  	
  dispatcher('test')	
  {	
  
	
  	
  	
  	
  abstract	
  Object	
  createNode(Object	
  name,	
  Object	
  value)	
  
	
  	
  	
  	
  abstract	
  Object	
  createNode(Object	
  name,	
  Map	
  attributes)	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  type	
  =	
  DispatcherType.SYNCHRONOUS	
  
	
  	
  	
  	
  abstract	
  Object	
  createNode(Object	
  name,	
  Map	
  attributes,	
  Object	
  value)	
  
}	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  

	
  	
  	
  	
  }	
  
}

@glaforge — @smaldini / #DV13-rtweb

!53
GPath expressions
• GPath expressions are like XPath 

but for an object graph
import	
  groovy.json.*	
  
!

def	
  url	
  =	
  "https://api.github.com/repos/groovy/groovy-­‐core/commits"	
  
!

def	
  commits	
  =	
  new	
  JsonSlurper().parseText(url.toURL().text)	
  
!

assert	
  commits[0].commit.author.name	
  ==	
  'Cedric	
  Champeau'

@glaforge — @smaldini / #DV13-rtweb

!54
GPath expressions
• GPath expressions are like XPath 

but for an object graph
import	
  groovy.json.*	
  
!

def	
  url	
  =	
  "https://api.github.com/repos/groovy/groovy-­‐core/commits"	
  
!

def	
  commits	
  =	
  new	
  JsonSlurper().parseText(url.toURL().text)	
  
!

assert	
  commits[0].commit.author.name	
  ==	
  'Cedric	
  Champeau'

GPath expression

@glaforge — @smaldini / #DV13-rtweb

!54
GPath expressions
• GPath expressions are like XPath 

but for an object graph
import	
  groovy.json.*	
  
!

def	
  url	
  =	
  "https://api.github.com/repos/groovy/groovy-­‐core/commits"	
  
!

def	
  commits	
  =	
  new	
  JsonSlurper().parseText(url.toURL().text)	
  
!

assert	
  commits[0].commit.author.name	
  ==	
  'Cedric	
  Champeau'

GPath expression

@glaforge — @smaldini / #DV13-rtweb

Add find / findAll
into the mix
!54
GPath expressions
• GPath expressions are like XPath 

but for an object graph

No (un)marshalling!

import	
  groovy.json.*	
  
!

def	
  url	
  =	
  "https://api.github.com/repos/groovy/groovy-­‐core/commits"	
  
!

def	
  commits	
  =	
  new	
  JsonSlurper().parseText(url.toURL().text)	
  
!

assert	
  commits[0].commit.author.name	
  ==	
  'Cedric	
  Champeau'

GPath expression

@glaforge — @smaldini / #DV13-rtweb

Add find / findAll
into the mix
!54
Lists
def	
  list	
  =	
  ['a',	
  'b',	
  'c']	
  
!

list	
  <<	
  'd'	
  
assert	
  list.contains('d')	
  
!

assert	
  list.findAll	
  {	
  it.startsWith	
  'a'	
  }.size()	
  ==	
  1	
  
assert	
  list.collect	
  {	
  it.toUpperCase()	
  }	
  

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ==	
  ['A',	
  'B',	
  'C',	
  'D']	
  
assert	
  list.inject('')	
  {	
  a,	
  b	
  -­‐>	
  a	
  +	
  b	
  }	
  ==	
  'abcd'

@glaforge — @smaldini / #DV13-rtweb

!55
Lists
List definition
def	
  list	
  =	
  ['a',	
  'b',	
  'c']	
  
!

list	
  <<	
  'd'	
  
assert	
  list.contains('d')	
  
!

assert	
  list.findAll	
  {	
  it.startsWith	
  'a'	
  }.size()	
  ==	
  1	
  
assert	
  list.collect	
  {	
  it.toUpperCase()	
  }	
  

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ==	
  ['A',	
  'B',	
  'C',	
  'D']	
  
assert	
  list.inject('')	
  {	
  a,	
  b	
  -­‐>	
  a	
  +	
  b	
  }	
  ==	
  'abcd'

@glaforge — @smaldini / #DV13-rtweb

!55
Lists
List definition
def	
  list	
  =	
  ['a',	
  'b',	
  'c']	
  
!

list	
  <<	
  'd'	
  
assert	
  list.contains('d')	
  

Append an element
(operator overloading)

!

assert	
  list.findAll	
  {	
  it.startsWith	
  'a'	
  }.size()	
  ==	
  1	
  
assert	
  list.collect	
  {	
  it.toUpperCase()	
  }	
  

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ==	
  ['A',	
  'B',	
  'C',	
  'D']	
  
assert	
  list.inject('')	
  {	
  a,	
  b	
  -­‐>	
  a	
  +	
  b	
  }	
  ==	
  'abcd'

@glaforge — @smaldini / #DV13-rtweb

!55
Lists
List definition
def	
  list	
  =	
  ['a',	
  'b',	
  'c']	
  
!

list	
  <<	
  'd'	
  
assert	
  list.contains('d')	
  

Append an element
(operator overloading)

!

assert	
  list.findAll	
  {	
  it.startsWith	
  'a'	
  }.size()	
  ==	
  1	
  
assert	
  list.collect	
  {	
  it.toUpperCase()	
  }	
  

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ==	
  ['A',	
  'B',	
  'C',	
  'D']	
  
assert	
  list.inject('')	
  {	
  a,	
  b	
  -­‐>	
  a	
  +	
  b	
  }	
  ==	
  'abcd'

Functional-style map /
filter / reduce with
closures
@glaforge — @smaldini / #DV13-rtweb

!55
Maps

def	
  map	
  =	
  [name:	
  'Guillaume',	
  age:	
  36]	
  
!

map.daughters	
  =	
  ['Marion',	
  'Erine']	
  
!

assert	
  map['daughters'].contains('Marion')

@glaforge — @smaldini / #DV13-rtweb

!56
Maps
Map definition
def	
  map	
  =	
  [name:	
  'Guillaume',	
  age:	
  36]	
  
!

map.daughters	
  =	
  ['Marion',	
  'Erine']	
  
!

assert	
  map['daughters'].contains('Marion')

@glaforge — @smaldini / #DV13-rtweb

!56
Maps
Map definition
def	
  map	
  =	
  [name:	
  'Guillaume',	
  age:	
  36]	
  
!

map.daughters	
  =	
  ['Marion',	
  'Erine']	
  
!

assert	
  map['daughters'].contains('Marion')

Indexed access

@glaforge — @smaldini / #DV13-rtweb

!56
Maps
Map definition
def	
  map	
  =	
  [name:	
  'Guillaume',	
  age:	
  36]	
  
!

map.daughters	
  =	
  ['Marion',	
  'Erine']	
  
!

assert	
  map['daughters'].contains('Marion')

Property notation
access
@glaforge — @smaldini / #DV13-rtweb

Indexed access

!56
Regular expressions
def	
  pattern	
  =	
  ~/.*foo.*/	
  
!

assert	
  "Alibaba"	
  ==~	
  /.*(ba){2}/	
  
!

def	
  matcher	
  =	
  "Superman"	
  =~	
  /([A-­‐Z][a-­‐z]+)man/	
  
assert	
  matcher[0][0]	
  ==	
  'Superman'	
  
assert	
  matcher[0][1]	
  ==	
  'Super'	
  
!

'75001	
  Paris'.find(/(d{5})s(w+)/)	
  {	
  match,	
  zip,	
  town	
  -­‐>	
  
	
  	
  	
  	
  println	
  "The	
  Zip	
  code	
  of	
  ${town}	
  is	
  ${zip}"	
  
}

@glaforge — @smaldini / #DV13-rtweb

!57
Regular expressions
Pattern
def	
  pattern	
  =	
  ~/.*foo.*/	
  
!

assert	
  "Alibaba"	
  ==~	
  /.*(ba){2}/	
  
!

def	
  matcher	
  =	
  "Superman"	
  =~	
  /([A-­‐Z][a-­‐z]+)man/	
  
assert	
  matcher[0][0]	
  ==	
  'Superman'	
  
assert	
  matcher[0][1]	
  ==	
  'Super'	
  
!

'75001	
  Paris'.find(/(d{5})s(w+)/)	
  {	
  match,	
  zip,	
  town	
  -­‐>	
  
	
  	
  	
  	
  println	
  "The	
  Zip	
  code	
  of	
  ${town}	
  is	
  ${zip}"	
  
}

@glaforge — @smaldini / #DV13-rtweb

!57
Regular expressions
Pattern
def	
  pattern	
  =	
  ~/.*foo.*/	
  

Match

!

assert	
  "Alibaba"	
  ==~	
  /.*(ba){2}/	
  
!

def	
  matcher	
  =	
  "Superman"	
  =~	
  /([A-­‐Z][a-­‐z]+)man/	
  
assert	
  matcher[0][0]	
  ==	
  'Superman'	
  
assert	
  matcher[0][1]	
  ==	
  'Super'	
  
!

'75001	
  Paris'.find(/(d{5})s(w+)/)	
  {	
  match,	
  zip,	
  town	
  -­‐>	
  
	
  	
  	
  	
  println	
  "The	
  Zip	
  code	
  of	
  ${town}	
  is	
  ${zip}"	
  
}

@glaforge — @smaldini / #DV13-rtweb

!57
Regular expressions
Pattern
def	
  pattern	
  =	
  ~/.*foo.*/	
  

Match

!

assert	
  "Alibaba"	
  ==~	
  /.*(ba){2}/	
  

Find

!

def	
  matcher	
  =	
  "Superman"	
  =~	
  /([A-­‐Z][a-­‐z]+)man/	
  
assert	
  matcher[0][0]	
  ==	
  'Superman'	
  
assert	
  matcher[0][1]	
  ==	
  'Super'	
  
!

'75001	
  Paris'.find(/(d{5})s(w+)/)	
  {	
  match,	
  zip,	
  town	
  -­‐>	
  
	
  	
  	
  	
  println	
  "The	
  Zip	
  code	
  of	
  ${town}	
  is	
  ${zip}"	
  
}

@glaforge — @smaldini / #DV13-rtweb

!57
Regular expressions
Pattern
def	
  pattern	
  =	
  ~/.*foo.*/	
  

Match

!

assert	
  "Alibaba"	
  ==~	
  /.*(ba){2}/	
  

Find

!

def	
  matcher	
  =	
  "Superman"	
  =~	
  /([A-­‐Z][a-­‐z]+)man/	
  
assert	
  matcher[0][0]	
  ==	
  'Superman'	
  
assert	
  matcher[0][1]	
  ==	
  'Super'	
  
!

'75001	
  Paris'.find(/(d{5})s(w+)/)	
  {	
  match,	
  zip,	
  town	
  -­‐>	
  
	
  	
  	
  	
  println	
  "The	
  Zip	
  code	
  of	
  ${town}	
  is	
  ${zip}"	
  
}

Nice way to decompose the matched regions
@glaforge — @smaldini / #DV13-rtweb

!57
Ranges
def	
  range	
  =	
  'a'..'z'	
  
!

assert	
  range.contains('m')	
  
assert	
  range.contains('z')	
  
!

def	
  exclusive	
  =	
  1..<10	
  
!

assert	
  !exclusive.contains(10)	
  
!

def	
  reverse	
  =	
  10..0	
  
!

assert	
  reverse[0]	
  ==	
  10	
  
assert	
  reverse[-­‐1]	
  ==	
  0
@glaforge — @smaldini / #DV13-rtweb

!58
Ranges

Range

def	
  range	
  =	
  'a'..'z'	
  
!

assert	
  range.contains('m')	
  
assert	
  range.contains('z')	
  
!

def	
  exclusive	
  =	
  1..<10	
  
!

assert	
  !exclusive.contains(10)	
  
!

def	
  reverse	
  =	
  10..0	
  
!

assert	
  reverse[0]	
  ==	
  10	
  
assert	
  reverse[-­‐1]	
  ==	
  0
@glaforge — @smaldini / #DV13-rtweb

!58
Ranges

Range

def	
  range	
  =	
  'a'..'z'	
  
!

assert	
  range.contains('m')	
  
assert	
  range.contains('z')	
  
!

def	
  exclusive	
  =	
  1..<10	
  

Excluded upper bound

!

assert	
  !exclusive.contains(10)	
  
!

def	
  reverse	
  =	
  10..0	
  
!

assert	
  reverse[0]	
  ==	
  10	
  
assert	
  reverse[-­‐1]	
  ==	
  0
@glaforge — @smaldini / #DV13-rtweb

!58
Ranges

Range

def	
  range	
  =	
  'a'..'z'	
  
!

assert	
  range.contains('m')	
  
assert	
  range.contains('z')	
  
!

def	
  exclusive	
  =	
  1..<10	
  

Excluded upper bound

!

assert	
  !exclusive.contains(10)	
  
!

def	
  reverse	
  =	
  10..0	
  

Reverse range

!

assert	
  reverse[0]	
  ==	
  10	
  
assert	
  reverse[-­‐1]	
  ==	
  0
@glaforge — @smaldini / #DV13-rtweb

!58
Ranges

Range

def	
  range	
  =	
  'a'..'z'	
  
!

assert	
  range.contains('m')	
  
assert	
  range.contains('z')	
  
!

def	
  exclusive	
  =	
  1..<10	
  

Excluded upper bound

!

assert	
  !exclusive.contains(10)	
  
!

def	
  reverse	
  =	
  10..0	
  

Reverse range

!

assert	
  reverse[0]	
  ==	
  10	
  
assert	
  reverse[-­‐1]	
  ==	
  0
@glaforge — @smaldini / #DV13-rtweb

Negative index count
from the end
!58
Strings, GStrings, multiline strings

def	
  name	
  =	
  'Groovy'	
  
def	
  tmpl	
  =	
  """	
  
	
  	
  	
  	
  Dear	
  Mr	
  ${name},	
  
	
  	
  	
  	
  You're	
  the	
  winner	
  of	
  the	
  lottery!	
  
	
  	
  	
  	
  Yours	
  sincerly,	
  
	
  	
  	
  	
  Dave	
  
"""	
  
!

assert	
  tmpl.toString().contains('Groovy')
@glaforge — @smaldini / #DV13-rtweb

!59
Strings, GStrings, multiline strings
Plain java.lang.String
def	
  name	
  =	
  'Groovy'	
  
def	
  tmpl	
  =	
  """	
  
	
  	
  	
  	
  Dear	
  Mr	
  ${name},	
  
	
  	
  	
  	
  You're	
  the	
  winner	
  of	
  the	
  lottery!	
  
	
  	
  	
  	
  Yours	
  sincerly,	
  
	
  	
  	
  	
  Dave	
  
"""	
  
!

assert	
  tmpl.toString().contains('Groovy')
@glaforge — @smaldini / #DV13-rtweb

!59
Strings, GStrings, multiline strings
Plain java.lang.String
def	
  name	
  =	
  'Groovy'	
  
Multiline string with
def	
  tmpl	
  =	
  """	
  
expression interpolation
	
  	
  	
  	
  Dear	
  Mr	
  ${name},	
  
	
  	
  	
  	
  You're	
  the	
  winner	
  of	
  the	
  lottery!	
  
	
  	
  	
  	
  Yours	
  sincerly,	
  
	
  	
  	
  	
  Dave	
  
"""	
  
!

assert	
  tmpl.toString().contains('Groovy')
@glaforge — @smaldini / #DV13-rtweb

!59
Surprising numbers...

System.out.println(	
  2.0	
  -­‐	
  1.1	
  );

@glaforge — @smaldini / #DV13-rtweb

!60
Surprising numbers...

System.out.println(	
  2.0	
  -­‐	
  1.1	
  );
0.8999999999999999

@glaforge — @smaldini / #DV13-rtweb

!60
Surprising numbers...

System.out.println(	
  2.0	
  -­‐	
  1.1	
  );
0.8999999999999999

@glaforge — @smaldini / #DV13-rtweb

!60
Surprising numbers...

System.out.println(	
  3	
  /	
  2	
  );

@glaforge — @smaldini / #DV13-rtweb

!61
Surprising numbers...

System.out.println(	
  3	
  /	
  2	
  );

1

@glaforge — @smaldini / #DV13-rtweb

!61
Surprising numbers...

System.out.println(	
  3	
  /	
  2	
  );

1

@glaforge — @smaldini / #DV13-rtweb

!61
BigDecimal by default!

assert	
  2.0	
  -­‐	
  1.1	
  ==	
  0.9
assert	
  3	
  /	
  2	
  ==	
  1.5

@glaforge — @smaldini / #DV13-rtweb

!62
BigDecimal by default!

assert	
  2.0	
  -­‐	
  1.1	
  ==	
  0.9
assert	
  3	
  /	
  2	
  ==	
  1.5
One of the reasons why microbenchmarks sometimes showed
Groovy to be slow...
@glaforge — @smaldini / #DV13-rtweb

!62
BigDecimal by default!

assert	
  2.0	
  -­‐	
  1.1	
  ==	
  0.9
assert	
  3	
  /	
  2	
  ==	
  1.5
One of the reasons why microbenchmarks sometimes showed
Groovy to be slow...
@glaforge — @smaldini / #DV13-rtweb

But you can use doubles & floats for
performance, with ‘d’ or ‘f ’ suffixes
or with explicit type
!62
Powerful switch /
case on steroids
Powerful switch /
case on steroids
switch(obj)	
  {	
  
	
  	
  	
  	
  case	
  123:	
  	
  	
  	
  	
  	
  	
  	
  	
  "number	
  123";	
  	
  	
  	
  	
  	
  	
  break	
  
	
  	
  	
  	
  case	
  "abc":	
  	
  	
  	
  	
  	
  	
  "string	
  abc";	
  	
  	
  	
  	
  	
  	
  break	
  
	
  	
  	
  	
  case	
  String:	
  	
  	
  	
  	
  	
  "is	
  a	
  string";	
  	
  	
  	
  	
  	
  break	
  
	
  	
  	
  	
  case	
  [1,	
  2,	
  3]:	
  	
  	
  "in	
  list";	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  break	
  
	
  	
  	
  	
  case	
  ~/.*o+.*/:	
  	
  	
  "regex	
  match";	
  	
  	
  	
  	
  	
  break	
  
	
  	
  	
  	
  case	
  {	
  it	
  <	
  3	
  }:	
  	
  "closure	
  criteria";	
  break	
  
	
  	
  	
  	
  default:	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "unknown"	
  
}
Named arguments

move	
  obj,	
  x:	
  3,	
  y:	
  4

@glaforge — @smaldini / #DV13-rtweb

!64
Named arguments

move	
  obj,	
  x:	
  3,	
  y:	
  4
Normal argument

@glaforge — @smaldini / #DV13-rtweb

!64
Named arguments

move	
  obj,	
  x:	
  3,	
  y:	
  4
Normal argument

@glaforge — @smaldini / #DV13-rtweb

Named argument

!64
Named arguments

move	
  obj,	
  x:	
  3,	
  y:	
  4
Normal argument

Named argument

Calls:
move(Map m, Object)

@glaforge — @smaldini / #DV13-rtweb

!64
Command chains
• Ability to chain method calls without parentheses and dots

move	
  forward	
  at	
  3.km/h

@glaforge — @smaldini / #DV13-rtweb

!65
Command chains
• Ability to chain method calls without parentheses and dots

move	
  forward	
  at	
  3.km/h
Actually equivalent to:
move(forward).at(3.getKm().div(h))

@glaforge — @smaldini / #DV13-rtweb

!65
Named arguments & command chains

check	
  that:	
  vodka	
  tastes	
  good

@glaforge — @smaldini / #DV13-rtweb

!66
Named arguments & command chains

check	
  that:	
  vodka	
  tastes	
  good
Will call:
check(that: vodka).tastes(good)

@glaforge — @smaldini / #DV13-rtweb

!66
Multiple assignment and destructuring
def	
  (a,	
  b)	
  =	
  ['A',	
  'B']	
  
!

(a,	
  b)	
  =	
  [b,	
  a]	
  
!

def	
  (int	
  i,	
  int	
  j)	
  =	
  [1,	
  2]	
  
!

def	
  geocode(String	
  place)	
  {	
  
	
  	
  	
  	
  return	
  [45.4,	
  2.3]	
  
}	
  
!

def	
  (la,	
  lo)	
  =	
  geocode("Paris")	
  
!

assert	
  la	
  ==	
  45.4	
  &&	
  lo	
  ==	
  2.3
@glaforge — @smaldini / #DV13-rtweb

!67
Multiple assignment and destructuring
def	
  (a,	
  b)	
  =	
  ['A',	
  'B']	
  
!

(a,	
  b)	
  =	
  [b,	
  a]	
  

Classic « swap »

!

def	
  (int	
  i,	
  int	
  j)	
  =	
  [1,	
  2]	
  
!

def	
  geocode(String	
  place)	
  {	
  
	
  	
  	
  	
  return	
  [45.4,	
  2.3]	
  
}	
  
!

def	
  (la,	
  lo)	
  =	
  geocode("Paris")	
  
!

assert	
  la	
  ==	
  45.4	
  &&	
  lo	
  ==	
  2.3
@glaforge — @smaldini / #DV13-rtweb

!67
Multiple assignment and destructuring
def	
  (a,	
  b)	
  =	
  ['A',	
  'B']	
  
!

With types

(a,	
  b)	
  =	
  [b,	
  a]	
  

Classic « swap »

!

def	
  (int	
  i,	
  int	
  j)	
  =	
  [1,	
  2]	
  
!

def	
  geocode(String	
  place)	
  {	
  
	
  	
  	
  	
  return	
  [45.4,	
  2.3]	
  
}	
  
!

def	
  (la,	
  lo)	
  =	
  geocode("Paris")	
  
!

assert	
  la	
  ==	
  45.4	
  &&	
  lo	
  ==	
  2.3
@glaforge — @smaldini / #DV13-rtweb

!67
Multiple assignment and destructuring
def	
  (a,	
  b)	
  =	
  ['A',	
  'B']	
  
!

With types

(a,	
  b)	
  =	
  [b,	
  a]	
  

Classic « swap »

!

def	
  (int	
  i,	
  int	
  j)	
  =	
  [1,	
  2]	
  
!

Method
returning a list

def	
  geocode(String	
  place)	
  {	
  
	
  	
  	
  	
  return	
  [45.4,	
  2.3]	
  
}	
  
!

def	
  (la,	
  lo)	
  =	
  geocode("Paris")	
  
!

assert	
  la	
  ==	
  45.4	
  &&	
  lo	
  ==	
  2.3
@glaforge — @smaldini / #DV13-rtweb

!67
Multiple assignment and destructuring
def	
  (a,	
  b)	
  =	
  ['A',	
  'B']	
  
!

With types

(a,	
  b)	
  =	
  [b,	
  a]	
  

Classic « swap »

!

def	
  (int	
  i,	
  int	
  j)	
  =	
  [1,	
  2]	
  
!

Method
returning a list

def	
  geocode(String	
  place)	
  {	
  
	
  	
  	
  	
  return	
  [45.4,	
  2.3]	
  
}	
  
Destructuring
!

def	
  (la,	
  lo)	
  =	
  geocode("Paris")	
  
!

assert	
  la	
  ==	
  45.4	
  &&	
  lo	
  ==	
  2.3
@glaforge — @smaldini / #DV13-rtweb

!67
Multiple assignment and destructuring
class	
  Point	
  {	
  
	
  	
  	
  	
  double	
  x,	
  y	
  
!

	
  	
  	
  	
  double	
  getAt(int	
  idx)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  if	
  (idx	
  ==	
  0)	
  x	
  
	
  	
  	
  	
  	
  	
  	
  	
  else	
  if	
  (idx	
  ==	
  1)	
  y	
  
	
  	
  	
  	
  	
  	
  	
  	
  else	
  throw	
  new	
  Exception("Wrong	
  index")	
  
	
  	
  	
  	
  }	
  
}	
  
!

def	
  (x,	
  y)	
  =	
  new	
  Point(x:	
  48.3,	
  y:	
  3.5)	
  
!

assert	
  x	
  ==	
  48.3	
  &&	
  y	
  ==	
  3.5
@glaforge — @smaldini / #DV13-rtweb

!68
Multiple assignment and destructuring
class	
  Point	
  {	
  
	
  	
  	
  	
  double	
  x,	
  y	
  

Method signature
convention: getAt(int)

!

	
  	
  	
  	
  double	
  getAt(int	
  idx)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  if	
  (idx	
  ==	
  0)	
  x	
  
	
  	
  	
  	
  	
  	
  	
  	
  else	
  if	
  (idx	
  ==	
  1)	
  y	
  
	
  	
  	
  	
  	
  	
  	
  	
  else	
  throw	
  new	
  Exception("Wrong	
  index")	
  
	
  	
  	
  	
  }	
  
}	
  
!

def	
  (x,	
  y)	
  =	
  new	
  Point(x:	
  48.3,	
  y:	
  3.5)	
  
!

assert	
  x	
  ==	
  48.3	
  &&	
  y	
  ==	
  3.5
@glaforge — @smaldini / #DV13-rtweb

!68
Multiple assignment and destructuring
class	
  Point	
  {	
  
	
  	
  	
  	
  double	
  x,	
  y	
  

Method signature
convention: getAt(int)

!

	
  	
  	
  	
  double	
  getAt(int	
  idx)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  if	
  (idx	
  ==	
  0)	
  x	
  
	
  	
  	
  	
  	
  	
  	
  	
  else	
  if	
  (idx	
  ==	
  1)	
  y	
  
	
  	
  	
  	
  	
  	
  	
  	
  else	
  throw	
  new	
  Exception("Wrong	
  index")	
  
	
  	
  	
  	
  }	
  
}	
  
Transparent destructuring
!

def	
  (x,	
  y)	
  =	
  new	
  Point(x:	
  48.3,	
  y:	
  3.5)	
  
!

assert	
  x	
  ==	
  48.3	
  &&	
  y	
  ==	
  3.5
@glaforge — @smaldini / #DV13-rtweb

!68
Operator overloading
import	
  static	
  Unit.*	
  
!

enum	
  Unit	
  {	
  
	
  	
  M(1),	
  KM(1000)	
  
!

	
  	
  double	
  mult	
  
	
  	
  Unit(double	
  mult)	
  {	
  
	
  	
  	
  	
  this.mult	
  =	
  mult	
  
	
  	
  }	
  
}

@glaforge — @smaldini / #DV13-rtweb

!69
Operator overloading
import	
  static	
  Unit.*	
  
!

enum	
  Unit	
  {	
  
	
  	
  M(1),	
  KM(1000)	
  
!

import	
  groovy.transform.Immutable	
  
import	
  static	
  Unit.*	
  

	
  	
  double	
  mult	
  
	
  	
  Unit(double	
  mult)	
  {	
   !
	
  	
  	
  	
  this.mult	
  =	
  mult	
   @Immutable	
  
	
  	
  }	
  
class	
  Distance	
  {	
  
}
	
  	
  double	
  q	
  
	
  	
  Unit	
  u	
  
!

	
  	
  Distance	
  plus(Distance	
  d)	
  {	
  
	
  	
  	
  	
  new	
  Distance(	
  	
  q	
  *	
  	
  	
  u.mult	
  +	
  

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  d.q	
  *	
  d.u.mult,	
  M)	
  
	
  	
  }	
  
}
@glaforge — @smaldini / #DV13-rtweb

!69
Operator overloading
import	
  static	
  Unit.*	
  
!

import	
  static	
  Unit.*	
  

enum	
  Unit	
  {	
  
	
  	
  M(1),	
  KM(1000)	
  

!

def	
  d10	
  =	
  new	
  Distance(10,	
  M)	
  
!
import	
  groovy.transform.Immutable	
  
def	
  d15	
  =	
  new	
  Distance(15,	
  M)	
  
	
  	
  double	
  mult	
  
import	
  static	
  Unit.*	
  
!
	
  	
  Unit(double	
  mult)	
  {	
   !
def	
  d25	
  =	
  d10	
  +	
  d15	
  
	
  	
  	
  	
  this.mult	
  =	
  mult	
   @Immutable	
  
!
	
  	
  }	
  
class	
  Distance	
  {	
  
assert	
  d25.q	
  ==	
  25	
  &&	
  d25.u	
  ==	
  M
}
	
  	
  double	
  q	
  
	
  	
  Unit	
  u	
  
!

	
  	
  Distance	
  plus(Distance	
  d)	
  {	
  
	
  	
  	
  	
  new	
  Distance(	
  	
  q	
  *	
  	
  	
  u.mult	
  +	
  

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  d.q	
  *	
  d.u.mult,	
  M)	
  
	
  	
  }	
  
}
@glaforge — @smaldini / #DV13-rtweb

!69
Operator overloading
import	
  static	
  Unit.*	
  
!

import	
  static	
  Unit.*	
  

enum	
  Unit	
  {	
  
	
  	
  M(1),	
  KM(1000)	
  

!

def	
  d10	
  =	
  new	
  Distance(10,	
  M)	
  
!
import	
  groovy.transform.Immutable	
  
def	
  d15	
  =	
  new	
  Distance(15,	
  M)	
  
	
  	
  double	
  mult	
  
import	
  static	
  Unit.*	
  
!
	
  	
  Unit(double	
  mult)	
  {	
   !
def	
  d25	
  =	
  d10	
  +	
  d15	
  
	
  	
  	
  	
  this.mult	
  =	
  mult	
   @Immutable	
  
!
	
  	
  }	
  
class	
  Distance	
  {	
  
assert	
  d25.q	
  ==	
  25	
  &&	
  d25.u	
  ==	
  M
}
	
  	
  double	
  q	
  
	
  	
  Unit	
  u	
  

Overload the ‘+’
operator

@glaforge — @smaldini / #DV13-rtweb

!

	
  	
  Distance	
  plus(Distance	
  d)	
  {	
  
	
  	
  	
  	
  new	
  Distance(	
  	
  q	
  *	
  	
  	
  u.mult	
  +	
  

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  d.q	
  *	
  d.u.mult,	
  M)	
  
	
  	
  }	
  
}
!69
Operator overloading
import	
  static	
  Unit.*	
  
!

import	
  static	
  Unit.*	
  

enum	
  Unit	
  {	
  
	
  	
  M(1),	
  KM(1000)	
  

!

def	
  d10	
  =	
  new	
  Distance(10,	
  M)	
  
!
import	
  groovy.transform.Immutable	
  
def	
  d15	
  =	
  new	
  Distance(15,	
  M)	
  
	
  	
  double	
  mult	
  
import	
  static	
  Unit.*	
  
!
	
  	
  Unit(double	
  mult)	
  {	
   !
def	
  d25	
  =	
  d10	
  +	
  d15	
  
	
  	
  	
  	
  this.mult	
  =	
  mult	
   @Immutable	
  
!
	
  	
  }	
  
class	
  Distance	
  {	
  
assert	
  d25.q	
  ==	
  25	
  &&	
  d25.u	
  ==	
  M
}
	
  	
  double	
  q	
  
	
  	
  Unit	
  u	
  

Overload the ‘+’
operator

@glaforge — @smaldini / #DV13-rtweb

!

	
  	
  Distance	
  plus(Distance	
  d)	
  {	
  
	
  	
  	
  	
  new	
  Distance(	
  	
  q	
  *	
  	
  	
  u.mult	
  +	
  

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  d.q	
  *	
  d.u.mult,	
  M)	
  
	
  	
  }	
  
}

Use ‘+’

!69
Operator overloading
a	
  +	
  b	
  	
  	
  //	
  a.plus(b)	
  
a	
  -­‐	
  b	
  	
  	
  //	
  a.minus(b)	
  
a	
  *	
  b	
  	
  	
  //	
  a.multiply(b)	
  
a	
  /	
  b	
  	
  	
  //	
  a.div(b)	
  
a	
  %	
  b	
  	
  	
  //	
  a.modulo(b)	
  
a	
  **	
  b	
  	
  //	
  a.power(b)	
  
a	
  |	
  b	
  	
  	
  //	
  a.or(b)	
  
a	
  &	
  b	
  	
  	
  //	
  a.and(b)	
  
a	
  ^	
  b	
  	
  	
  //	
  a.xor(b)	
  
a[b]	
  	
  	
  	
  //	
  a.getAt(b)	
  
a	
  <<	
  b	
  	
  //	
  a.leftShift(b)	
  
a	
  >>	
  b	
  	
  //	
  a.rightShift(b)	
  
a	
  >>>	
  b	
  //	
  a.rightShiftUnsigned(b)	
  
+a	
  	
  	
  	
  	
  	
  //	
  a.unaryPlus()	
  
-­‐a	
  	
  	
  	
  	
  	
  //	
  a.unaryMinus()	
  
~a	
  	
  	
  	
  	
  	
  //	
  a.bitwiseNegate()
@glaforge — @smaldini / #DV13-rtweb

!70
Operator overloading
a	
  +	
  b	
  	
  	
  //	
  a.plus(b)	
  
a	
  -­‐	
  b	
  	
  	
  //	
  a.minus(b)	
  
a	
  *	
  b	
  	
  	
  //	
  a.multiply(b)	
  
Operator overloading is
a	
  /	
  b	
  	
  	
  //	
  a.div(b)	
  
a	
  %	
  b	
  	
  	
  //	
  a.modulo(b)	
  
just a convention on
a	
  **	
  b	
  	
  //	
  a.power(b)	
  
method names
a	
  |	
  b	
  	
  	
  //	
  a.or(b)	
  
a	
  &	
  b	
  	
  	
  //	
  a.and(b)	
  
a	
  ^	
  b	
  	
  	
  //	
  a.xor(b)	
  
a[b]	
  	
  	
  	
  //	
  a.getAt(b)	
  
a	
  <<	
  b	
  	
  //	
  a.leftShift(b)	
  
a	
  >>	
  b	
  	
  //	
  a.rightShift(b)	
  
a	
  >>>	
  b	
  //	
  a.rightShiftUnsigned(b)	
  
+a	
  	
  	
  	
  	
  	
  //	
  a.unaryPlus()	
  
-­‐a	
  	
  	
  	
  	
  	
  //	
  a.unaryMinus()	
  
~a	
  	
  	
  	
  	
  	
  //	
  a.bitwiseNegate()
@glaforge — @smaldini / #DV13-rtweb

!70
Power asserts
def	
  (a,	
  b,	
  c)	
  =	
  [20,	
  30,	
  40]	
  
!

assert	
  a	
  *	
  (b	
  -­‐	
  1)	
  /	
  10	
  ==	
  3	
  *	
  c	
  /	
  2	
  +	
  1

@glaforge — @smaldini / #DV13-rtweb

!71
Power asserts
def	
  (a,	
  b,	
  c)	
  =	
  [20,	
  30,	
  40]	
  
!

assert	
  a	
  *	
  (b	
  -­‐	
  1)	
  /	
  10	
  ==	
  3	
  *	
  c	
  /	
  2	
  +	
  1
Assertion	
  failed:	
  	
  
!

assert	
  a	
  *	
  (b	
  -­‐	
  1)	
  /	
  10	
  ==	
  3	
  *	
  c	
  /	
  2	
  +	
  1	
  
	
  	
  	
  	
  	
  	
  	
  |	
  |	
  	
  |	
  |	
  	
  	
  	
  |	
  	
  	
  	
  |	
  	
  	
  	
  |	
  |	
  |	
  	
  	
  |	
  
	
  	
  	
  	
  	
  	
  	
  |	
  580|	
  29	
  	
  	
  58	
  	
  	
  false|	
  |	
  60	
  	
  61	
  
	
  	
  	
  	
  	
  	
  	
  20	
  	
  	
  30	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  |	
  40	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  120	
  
!

	
   at	
  script1.run(script1.groovy:3)
@glaforge — @smaldini / #DV13-rtweb

!71
Power asserts
def	
  (a,	
  b,	
  c)	
  =	
  [20,	
  30,	
  40]	
  
!

assert	
  a	
  *	
  (b	
  -­‐	
  1)	
  /	
  10	
  ==	
  3	
  *	
  c	
  /	
  2	
  +	
  1
Assertion	
  failed:	
  	
  
!

assert	
  a	
  *	
  (b	
  -­‐	
  1)	
  /	
  10	
  ==	
  3	
  *	
  c	
  /	
  2	
  +	
  1	
  
	
  	
  	
  	
  	
  	
  	
  |	
  |	
  	
  |	
  |	
  	
  	
  	
  |	
  	
  	
  	
  |	
  	
  	
  	
  |	
  |	
  |	
  	
  	
  |	
  
	
  	
  	
  	
  	
  	
  	
  |	
  580|	
  29	
  	
  	
  58	
  	
  	
  false|	
  |	
  60	
  	
  61	
  
	
  	
  	
  	
  	
  	
  	
  20	
  	
  	
  30	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  |	
  40	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  120	
  
!

Invented by the Spock testing framework

	
   at	
  script1.run(script1.groovy:3)
@glaforge — @smaldini / #DV13-rtweb

!71
Null handling
class	
  Order	
  {	
  
	
  	
  	
  	
  LineItem	
  line	
  
}	
  
class	
  LineItem	
  {	
  
	
  	
  	
  	
  int	
  quantity	
  
	
  	
  	
  	
  Item	
  item	
  
}	
  
class	
  Item	
  {	
  
	
  	
  	
  	
  String	
  name	
  
}	
  
!

def	
  o	
  =	
  new	
  Order(	
  
	
  	
  	
  	
  line:	
  new	
  LineItem(	
  
	
  	
  	
  	
  	
  	
  	
  	
  quantity:	
  2,	
  
	
  	
  	
  	
  	
  	
  	
  	
  item:	
  null))	
  
!

println	
  o.line.item.name
@glaforge — @smaldini / #DV13-rtweb

!72
Null handling
class	
  Order	
  {	
  
	
  	
  	
  	
  LineItem	
  line	
  
}	
  
class	
  LineItem	
  {	
  
	
  	
  	
  	
  int	
  quantity	
  
	
  	
  	
  	
  Item	
  item	
  
}	
  
class	
  Item	
  {	
  
	
  	
  	
  	
  String	
  name	
  
}	
  
!

def	
  o	
  =	
  new	
  Order(	
  
	
  	
  	
  	
  line:	
  new	
  LineItem(	
  
	
  	
  	
  	
  	
  	
  	
  	
  quantity:	
  2,	
  
	
  	
  	
  	
  	
  	
  	
  	
  item:	
  null))	
  

With Java, you only get an NPE.
No idea where it came from!

!

println	
  o.line.item.name
@glaforge — @smaldini / #DV13-rtweb

!72
Null handling
class	
  Order	
  {	
  
	
  	
  	
  	
  LineItem	
  line	
  
}	
  
class	
  LineItem	
  {	
  
	
  	
  	
  	
  int	
  quantity	
  
	
  	
  	
  	
  Item	
  item	
  
}	
  
class	
  Item	
  {	
  
	
  	
  	
  	
  String	
  name	
  
}	
  
!

def	
  o	
  =	
  new	
  Order(	
  
	
  	
  	
  	
  line:	
  new	
  LineItem(	
  
	
  	
  	
  	
  	
  	
  	
  	
  quantity:	
  2,	
  
	
  	
  	
  	
  	
  	
  	
  	
  item:	
  null))	
  
!

println	
  o.line.item.name
@glaforge — @smaldini / #DV13-rtweb

With Java, you only get an NPE.
No idea where it came from!
Groovy will say:
Cannot get property ‘name’ on null object
!72
Null handling
class	
  Order	
  {	
  
	
  	
  	
  	
  LineItem	
  line	
  
}	
  
class	
  LineItem	
  {	
  
	
  	
  	
  	
  int	
  quantity	
  
	
  	
  	
  	
  Item	
  item	
  
}	
  
class	
  Item	
  {	
  
	
  	
  	
  	
  String	
  name	
  
}	
  
!

def	
  o	
  =	
  new	
  Order(	
  
	
  	
  	
  	
  line:	
  new	
  LineItem(	
  
	
  	
  	
  	
  	
  	
  	
  	
  quantity:	
  2,	
  
	
  	
  	
  	
  	
  	
  	
  	
  item:	
  null))	
  
!

println	
  o.line.item.name
@glaforge — @smaldini / #DV13-rtweb

!72
Null handling
class	
  Order	
  {	
  
	
  	
  	
  	
  LineItem	
  line	
  
}	
  
class	
  LineItem	
  {	
  
	
  	
  	
  	
  int	
  quantity	
  
	
  	
  	
  	
  Item	
  item	
  
}	
  
class	
  Item	
  {	
  
	
  	
  	
  	
  String	
  name	
  
}	
  

o?.line?.item?.name

!

def	
  o	
  =	
  new	
  Order(	
  
	
  	
  	
  	
  line:	
  new	
  LineItem(	
  
	
  	
  	
  	
  	
  	
  	
  	
  quantity:	
  2,	
  
	
  	
  	
  	
  	
  	
  	
  	
  item:	
  null))	
  
!

println	
  o.line.item.name
@glaforge — @smaldini / #DV13-rtweb

!72
Null handling
class	
  Order	
  {	
  
	
  	
  	
  	
  LineItem	
  line	
  
}	
  
class	
  LineItem	
  {	
  
	
  	
  	
  	
  int	
  quantity	
  
	
  	
  	
  	
  Item	
  item	
  
}	
  
class	
  Item	
  {	
  
	
  	
  	
  	
  String	
  name	
  
}	
  

o?.line?.item?.name
Safe navigation:
will just return
null; No NPE

!

def	
  o	
  =	
  new	
  Order(	
  
	
  	
  	
  	
  line:	
  new	
  LineItem(	
  
	
  	
  	
  	
  	
  	
  	
  	
  quantity:	
  2,	
  
	
  	
  	
  	
  	
  	
  	
  	
  item:	
  null))	
  
!

println	
  o.line.item.name
@glaforge — @smaldini / #DV13-rtweb

!72
The Truth,
the Groovy Truth!
The Truth,
the Groovy Truth!
And what if I could
customize the truth?
The Groovy Truth
assert	
  !(	
  null	
  )	
  
assert	
  !(	
  	
  ""	
  	
  )	
  
assert	
  !(	
  	
  []	
  	
  )	
  
assert	
  !(	
  	
  	
  0	
  	
  )
assert	
  new	
  Object()	
  
assert	
  "string"	
  
assert	
  [1,	
  2,	
  3]	
  
assert	
  1234
@glaforge — @smaldini / #DV13-rtweb

!74
The Groovy Truth
null, empty, 0-sized, zero
are coerced to false

assert	
  !(	
  null	
  )	
  
assert	
  !(	
  	
  ""	
  	
  )	
  
assert	
  !(	
  	
  []	
  	
  )	
  
assert	
  !(	
  	
  	
  0	
  	
  )

assert	
  new	
  Object()	
  
assert	
  "string"	
  
assert	
  [1,	
  2,	
  3]	
  
assert	
  1234
@glaforge — @smaldini / #DV13-rtweb

!74
The Groovy Truth
null, empty, 0-sized, zero
are coerced to false

assert	
  !(	
  null	
  )	
  
assert	
  !(	
  	
  ""	
  	
  )	
  
assert	
  !(	
  	
  []	
  	
  )	
  
assert	
  !(	
  	
  	
  0	
  	
  )

assert	
  new	
  Object()	
  
assert	
  "string"	
  
assert	
  [1,	
  2,	
  3]	
  
assert	
  1234
@glaforge — @smaldini / #DV13-rtweb

true otherwise

!74
Customizing the truth!
class	
  Account	
  {	
  
	
  	
  	
  	
  String	
  name	
  
	
  	
  	
  	
  boolean	
  disabled	
  =	
  false	
  
!

	
  	
  	
  	
  boolean	
  asBoolean()	
  {	
  !disabled	
  }	
  
}	
  
!

assert	
  	
  new	
  Account(name:	
  'current')	
  
assert	
  !new	
  Account(name:	
  'old',	
  disabled:	
  true)

@glaforge — @smaldini / #DV13-rtweb

!75
Customizing the truth!
class	
  Account	
  {	
  
	
  	
  	
  	
  String	
  name	
  
	
  	
  	
  	
  boolean	
  disabled	
  =	
  false	
  
!

	
  	
  	
  	
  boolean	
  asBoolean()	
  {	
  !disabled	
  }	
  
}	
  
!

assert	
  	
  new	
  Account(name:	
  'current')	
  
assert	
  !new	
  Account(name:	
  'old',	
  disabled:	
  true)

while (account), if (account), etc…
@glaforge — @smaldini / #DV13-rtweb

!75
?:
?:
The Elvis
operator!
Towards Elvis...

@glaforge — @smaldini / #DV13-rtweb

!77
Towards Elvis...
def	
  (x,	
  y)	
  =	
  ['MacBook	
  Pro',	
  'unknown']

@glaforge — @smaldini / #DV13-rtweb

!77
Towards Elvis...
def	
  (x,	
  y)	
  =	
  ['MacBook	
  Pro',	
  'unknown']

@glaforge — @smaldini / #DV13-rtweb

!77
Towards Elvis...
def	
  (x,	
  y)	
  =	
  ['MacBook	
  Pro',	
  'unknown']
if	
  (x	
  !=	
  null	
  &&	
  x.size()	
  >	
  0)	
  x	
  else	
  y

@glaforge — @smaldini / #DV13-rtweb

!77
Towards Elvis...
def	
  (x,	
  y)	
  =	
  ['MacBook	
  Pro',	
  'unknown']
if	
  (x	
  !=	
  null	
  &&	
  x.size()	
  >	
  0)	
  x	
  else	
  y
if	
  (x	
  &&	
  x.size())	
  x	
  else	
  y

@glaforge — @smaldini / #DV13-rtweb

!77
Towards Elvis...
def	
  (x,	
  y)	
  =	
  ['MacBook	
  Pro',	
  'unknown']
if	
  (x	
  !=	
  null	
  &&	
  x.size()	
  >	
  0)	
  x	
  else	
  y
if	
  (x	
  &&	
  x.size())	
  x	
  else	
  y
if	
  (x)	
  x	
  else	
  y

@glaforge — @smaldini / #DV13-rtweb

!77
Towards Elvis...
def	
  (x,	
  y)	
  =	
  ['MacBook	
  Pro',	
  'unknown']
if	
  (x	
  !=	
  null	
  &&	
  x.size()	
  >	
  0)	
  x	
  else	
  y
if	
  (x	
  &&	
  x.size())	
  x	
  else	
  y
if	
  (x)	
  x	
  else	
  y
x	
  ?	
  x	
  :	
  y

@glaforge — @smaldini / #DV13-rtweb

!77
Towards Elvis...
def	
  (x,	
  y)	
  =	
  ['MacBook	
  Pro',	
  'unknown']
if	
  (x	
  !=	
  null	
  &&	
  x.size()	
  >	
  0)	
  x	
  else	
  y
if	
  (x	
  &&	
  x.size())	
  x	
  else	
  y
if	
  (x)	
  x	
  else	
  y
x	
  ?	
  x	
  :	
  y
x	
  ?:	
  y

@glaforge — @smaldini / #DV13-rtweb

!77
Towards Elvis...
def	
  (x,	
  y)	
  =	
  ['MacBook	
  Pro',	
  'unknown']
if	
  (x	
  !=	
  null	
  &&	
  x.size()	
  >	
  0)	
  x	
  else	
  y
if	
  (x	
  &&	
  x.size())	
  x	
  else	
  y
if	
  (x)	
  x	
  else	
  y
x	
  ?	
  x	
  :	
  y
x	
  ?:	
  y

Null, empty, zerosized... false,
otherwise true!

@glaforge — @smaldini / #DV13-rtweb

!77
Towards Elvis...
def	
  (x,	
  y)	
  =	
  ['MacBook	
  Pro',	
  'unknown']
if	
  (x	
  !=	
  null	
  &&	
  x.size()	
  >	
  0)	
  x	
  else	
  y
if	
  (x	
  &&	
  x.size())	
  x	
  else	
  y
if	
  (x)	
  x	
  else	
  y
x	
  ?	
  x	
  :	
  y
x	
  ?:	
  y

Good old ternary
operator

@glaforge — @smaldini / #DV13-rtweb

Null, empty, zerosized... false,
otherwise true!

!77
Towards Elvis...
def	
  (x,	
  y)	
  =	
  ['MacBook	
  Pro',	
  'unknown']
if	
  (x	
  !=	
  null	
  &&	
  x.size()	
  >	
  0)	
  x	
  else	
  y
if	
  (x	
  &&	
  x.size())	
  x	
  else	
  y
if	
  (x)	
  x	
  else	
  y
x	
  ?	
  x	
  :	
  y
x	
  ?:	
  y

Elvis!

@glaforge — @smaldini / #DV13-rtweb

Good old ternary
operator

Null, empty, zerosized... false,
otherwise true!

!77
AST transformations
• Abstract Syntax Tree
– in memory representation of your program

before being compiled into bytecode	

!

• AST transformation == process of transforming the AST of a
program before it’s compiled	

!

• Macro-like compiler hook!

@glaforge — @smaldini / #DV13-rtweb

!78
Lots of AST transformations...
• Code generation	

– @ToString, @EqualsAndHashCode, @Canonical,
@TupleConstructor, @InheritConstructors, @Category,
@IndexedProperty, @Lazy, @Newify	


• Class design	

– @Delegate, @Immutable, @Memoized, 

@Singleton, @Mixin	


• Logging	

– @Log, @Log4j, @Log4j2, @Slf4j
@glaforge — @smaldini / #DV13-rtweb

!79
Lots of AST transformations...
• Safer scripting	

– @ConditionalInterrupt, @ThreadInterrupt, @TimedInterupt	


• Compiler directives	

– @Field, @PackageScope, @AnnotationCollector, @DelegatesTo,
@TypeChecked, @CompileStatic, @CompileDynamic	


• Swing patterns	

– @Bindable, @ListenerList, @Vetoable

@glaforge — @smaldini / #DV13-rtweb

!80
Lots of AST transformations...
• Dependencies handling	

– @Grab, @GrabConfig, @GrabExclude, @GrabResolver	


• Test assistance	

– @NotYetImplemented, @ASTTest

@glaforge — @smaldini / #DV13-rtweb

!81
Immutability
• Implement immutability 

by the book	

!

– final class	

– tuple-style constructor	

– private final backing fields	

– defensive copying of collections	

– equals() and hashCode() methods	

– toString() method	

– ...
@glaforge — @smaldini / #DV13-rtweb

!82
Immutability
• Implement immutability 

by the book	

!

Can be error-prone to
write immutable
classes oneself!

– final class	

– tuple-style constructor	

– private final backing fields	

– defensive copying of collections	

– equals() and hashCode() methods	

– toString() method	

– ...
@glaforge — @smaldini / #DV13-rtweb

!82
Immutability
• A Person class with	

– a String name	

– an int age

public final class Person {!
private final String name;!
private final int age;!

!
!
!
!
!

!

public Person(String name, int age) {!
this.name = name;!
this.age = age;!
}!
public String getName() {!
return name;!
}!
public int getAge() {!
return age;!
}!
public int hashCode() {!
return age + 31 * name.hashCode();!
}!
public boolean equals(Object other) {!
if (other == null) {!
return false;!
}!
if (this == other) {!
return true;!
}!
if (Person.class != other.getClass()) {!
return false;!
}!
Person otherPerson = (Person)other;!
if (!name.equals(otherPerson.getName()) {!
return false;!
}!
if (age != otherPerson.getAge()) {!
return false;!
}!
return true;!
}!
public String toString() {!
return "Person(" + name + ", " + age + ")";!
}!

}!

@glaforge — @smaldini / #DV13-rtweb

!83
Immutability
• A Person class with	

– a String name	

– an int age

public final class Person {!
private final String name;!
private final int age;!

!
!
!
!
!

!

public Person(String name, int age) {!
this.name = name;!
this.age = age;!
}!

Damn
verbose
Java!

public String getName() {!
return name;!
}!
public int getAge() {!
return age;!
}!
public int hashCode() {!
return age + 31 * name.hashCode();!
}!
public boolean equals(Object other) {!
if (other == null) {!
return false;!
}!
if (this == other) {!
return true;!
}!
if (Person.class != other.getClass()) {!
return false;!
}!
Person otherPerson = (Person)other;!
if (!name.equals(otherPerson.getName()) {!
return false;!
}!
if (age != otherPerson.getAge()) {!
return false;!
}!
return true;!
}!
public String toString() {!
return "Person(" + name + ", " + age + ")";!
}!

}!

@glaforge — @smaldini / #DV13-rtweb

!83
Immutability
• A Person class with	

– a String name	

– an int age

public final class Person {!
private final String name;!
private final int age;!

!
!
!
!
!

!

public Person(String name, int age) {!
this.name = name;!
this.age = age;!
}!

Damn
verbose
Java!

public String getName() {!
return name;!
}!
public int getAge() {!
return age;!
}!
public int hashCode() {!
return age + 31 * name.hashCode();!
}!
public boolean equals(Object other) {!
if (other == null) {!
return false;!
}!
if (this == other) {!
return true;!
}!
if (Person.class != other.getClass()) {!
return false;!
}!
Person otherPerson = (Person)other;!
if (!name.equals(otherPerson.getName()) {!
return false;!
}!
if (age != otherPerson.getAge()) {!
return false;!
}!
return true;!
}!

Although it’s also a
valid Groovy
program!

public String toString() {!
return "Person(" + name + ", " + age + ")";!
}!
}!

@glaforge — @smaldini / #DV13-rtweb

!83
@Immutable

import	
  groovy.transform.*	
  
!

@Immutable	
  
class	
  Person	
  {	
  
	
  	
  	
  	
  String	
  name	
  
	
  	
  	
  	
  int	
  age	
  
}
@glaforge — @smaldini / #DV13-rtweb

!84
Memoization
• Cache the result of previous invocations of closures or
methods with the same set of argument values
import	
  groovy.transform.*	
  
!

@Memoized	
  
long	
  fib(long	
  n)	
  {	
  
	
  	
  	
  	
  if	
  (n	
  ==	
  0)	
  0	
  
	
  	
  	
  	
  else	
  if	
  (n	
  ==	
  1)	
  1	
  
	
  	
  	
  	
  else	
  fib(n	
  -­‐	
  1)	
  +	
  fib(n	
  -­‐	
  2)	
  
}	
  
!

println	
  fib(40)
@glaforge — @smaldini / #DV13-rtweb

!85
Memoization
• Cache the result of previous invocations of closures or
methods with the same set of argument values
import	
  groovy.transform.*	
  

Best applied to
side-effect free
functions

!

@Memoized	
  
long	
  fib(long	
  n)	
  {	
  
	
  	
  	
  	
  if	
  (n	
  ==	
  0)	
  0	
  
	
  	
  	
  	
  else	
  if	
  (n	
  ==	
  1)	
  1	
  
	
  	
  	
  	
  else	
  fib(n	
  -­‐	
  1)	
  +	
  fib(n	
  -­‐	
  2)	
  
}	
  
!

println	
  fib(40)
@glaforge — @smaldini / #DV13-rtweb

!85
Groovy allows you
to be lazy
Groovy allows you
to be lazy

The compiler will do
the job for you
Groovy allows you
to be lazy

More concise, more
readable code

The compiler will do
the job for you
Groovy allows you
to be lazy

More concise, more
readable code

The compiler will do
the job for you

Less stuff to maintain
and worry about
@TypeChecked & @CompileStatic
• Static type checking with @TypeChecked, throws
compilation errors on...	

– typos in method and variable names	

– incompatible return types	

– wrong type assignments	

!

• Supports fine-grained type inference	

– « Least Upper Bound »	

– « Flow typing »

@glaforge — @smaldini / #DV13-rtweb

!87
@TypeChecked & @CompileStatic
• Static type checking with @TypeChecked, throws
compilation errors on...	

– typos in method and variable names	

– incompatible return types	

– wrong type assignments	

!

You can even extend the
static type checker!

• Supports fine-grained type inference	

– « Least Upper Bound »	

– « Flow typing »

@glaforge — @smaldini / #DV13-rtweb

!87
@TypeChecked & @CompileStatic
• Static type checking with @TypeChecked, throws
compilation errors on...	

– typos in method and variable names	

– incompatible return types	

– wrong type assignments	

!

You can even extend the
static type checker!

• Supports fine-grained type inference	

– « Least Upper Bound »	

– « Flow typing »

@glaforge — @smaldini / #DV13-rtweb

Type check DSLs or
dynamic features!
!87
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013
Groovy reactor grails realtime web   devoxx 2013

Weitere ähnliche Inhalte

Ähnlich wie Groovy reactor grails realtime web devoxx 2013

Groovy ネタ NGK 忘年会2009 ライトニングトーク
Groovy ネタ NGK 忘年会2009 ライトニングトークGroovy ネタ NGK 忘年会2009 ライトニングトーク
Groovy ネタ NGK 忘年会2009 ライトニングトークTsuyoshi Yamamoto
 
Groovy for java developers
Groovy for java developersGroovy for java developers
Groovy for java developersPuneet Behl
 
G3 Summit 2016 - Taking Advantage of Groovy Annotations
G3 Summit 2016 - Taking Advantage of Groovy AnnotationsG3 Summit 2016 - Taking Advantage of Groovy Annotations
G3 Summit 2016 - Taking Advantage of Groovy AnnotationsIván López Martín
 
Madrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovyMadrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovyIván López Martín
 
Greach 2015 AST – Groovy Transformers: More than meets the eye!
Greach 2015   AST – Groovy Transformers: More than meets the eye!Greach 2015   AST – Groovy Transformers: More than meets the eye!
Greach 2015 AST – Groovy Transformers: More than meets the eye!Iván López Martín
 
GeeCON Prague 2014 - Metaprogramming with Groovy
GeeCON Prague 2014 - Metaprogramming with GroovyGeeCON Prague 2014 - Metaprogramming with Groovy
GeeCON Prague 2014 - Metaprogramming with GroovyIván López Martín
 
Lift off with Groovy 2 at JavaOne 2013
Lift off with Groovy 2 at JavaOne 2013Lift off with Groovy 2 at JavaOne 2013
Lift off with Groovy 2 at JavaOne 2013Guillaume Laforge
 
Groovy for Java Developers
Groovy for Java DevelopersGroovy for Java Developers
Groovy for Java DevelopersAndres Almiray
 
ConFess Vienna 2015 - Metaprogramming with Groovy
ConFess Vienna 2015 - Metaprogramming with GroovyConFess Vienna 2015 - Metaprogramming with Groovy
ConFess Vienna 2015 - Metaprogramming with GroovyIván López Martín
 
Meetup di GDG Italia - Leonardo Pirro - Codemotion Rome 2018
Meetup di GDG Italia - Leonardo Pirro -  Codemotion Rome 2018 Meetup di GDG Italia - Leonardo Pirro -  Codemotion Rome 2018
Meetup di GDG Italia - Leonardo Pirro - Codemotion Rome 2018 Codemotion
 
Session inaugurale du Groovy User Group Paris
Session inaugurale du Groovy User Group ParisSession inaugurale du Groovy User Group Paris
Session inaugurale du Groovy User Group ParisGuillaume Laforge
 
Eclipsecon08 Introduction To Groovy
Eclipsecon08 Introduction To GroovyEclipsecon08 Introduction To Groovy
Eclipsecon08 Introduction To GroovyAndres Almiray
 
Corinna-2023.pptx
Corinna-2023.pptxCorinna-2023.pptx
Corinna-2023.pptxCurtis Poe
 
Eclipsecon09 Introduction To Groovy
Eclipsecon09 Introduction To GroovyEclipsecon09 Introduction To Groovy
Eclipsecon09 Introduction To GroovyAndres Almiray
 
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo....NET Conf UY
 
Wykorzystanie języka Kotlin do aplikacji na platformie Android
Wykorzystanie języka Kotlin do aplikacji na platformie AndroidWykorzystanie języka Kotlin do aplikacji na platformie Android
Wykorzystanie języka Kotlin do aplikacji na platformie Android3camp
 
Refactoring - Mejorando el diseño del código existente
Refactoring - Mejorando el diseño del código existenteRefactoring - Mejorando el diseño del código existente
Refactoring - Mejorando el diseño del código existenteMariano Sánchez
 
Introduction To Groovy
Introduction To GroovyIntroduction To Groovy
Introduction To Groovymanishkp84
 

Ähnlich wie Groovy reactor grails realtime web devoxx 2013 (20)

Groovy ネタ NGK 忘年会2009 ライトニングトーク
Groovy ネタ NGK 忘年会2009 ライトニングトークGroovy ネタ NGK 忘年会2009 ライトニングトーク
Groovy ネタ NGK 忘年会2009 ライトニングトーク
 
Presentatie - Introductie in Groovy
Presentatie - Introductie in GroovyPresentatie - Introductie in Groovy
Presentatie - Introductie in Groovy
 
Groovy for java developers
Groovy for java developersGroovy for java developers
Groovy for java developers
 
G3 Summit 2016 - Taking Advantage of Groovy Annotations
G3 Summit 2016 - Taking Advantage of Groovy AnnotationsG3 Summit 2016 - Taking Advantage of Groovy Annotations
G3 Summit 2016 - Taking Advantage of Groovy Annotations
 
Madrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovyMadrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovy
 
Greach 2015 AST – Groovy Transformers: More than meets the eye!
Greach 2015   AST – Groovy Transformers: More than meets the eye!Greach 2015   AST – Groovy Transformers: More than meets the eye!
Greach 2015 AST – Groovy Transformers: More than meets the eye!
 
GeeCON Prague 2014 - Metaprogramming with Groovy
GeeCON Prague 2014 - Metaprogramming with GroovyGeeCON Prague 2014 - Metaprogramming with Groovy
GeeCON Prague 2014 - Metaprogramming with Groovy
 
Lift off with Groovy 2 at JavaOne 2013
Lift off with Groovy 2 at JavaOne 2013Lift off with Groovy 2 at JavaOne 2013
Lift off with Groovy 2 at JavaOne 2013
 
Groovy for Java Developers
Groovy for Java DevelopersGroovy for Java Developers
Groovy for Java Developers
 
ConFess Vienna 2015 - Metaprogramming with Groovy
ConFess Vienna 2015 - Metaprogramming with GroovyConFess Vienna 2015 - Metaprogramming with Groovy
ConFess Vienna 2015 - Metaprogramming with Groovy
 
Meetup di GDG Italia - Leonardo Pirro - Codemotion Rome 2018
Meetup di GDG Italia - Leonardo Pirro -  Codemotion Rome 2018 Meetup di GDG Italia - Leonardo Pirro -  Codemotion Rome 2018
Meetup di GDG Italia - Leonardo Pirro - Codemotion Rome 2018
 
Session inaugurale du Groovy User Group Paris
Session inaugurale du Groovy User Group ParisSession inaugurale du Groovy User Group Paris
Session inaugurale du Groovy User Group Paris
 
Eclipsecon08 Introduction To Groovy
Eclipsecon08 Introduction To GroovyEclipsecon08 Introduction To Groovy
Eclipsecon08 Introduction To Groovy
 
Corinna-2023.pptx
Corinna-2023.pptxCorinna-2023.pptx
Corinna-2023.pptx
 
goatwork2014
goatwork2014goatwork2014
goatwork2014
 
Eclipsecon09 Introduction To Groovy
Eclipsecon09 Introduction To GroovyEclipsecon09 Introduction To Groovy
Eclipsecon09 Introduction To Groovy
 
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
 
Wykorzystanie języka Kotlin do aplikacji na platformie Android
Wykorzystanie języka Kotlin do aplikacji na platformie AndroidWykorzystanie języka Kotlin do aplikacji na platformie Android
Wykorzystanie języka Kotlin do aplikacji na platformie Android
 
Refactoring - Mejorando el diseño del código existente
Refactoring - Mejorando el diseño del código existenteRefactoring - Mejorando el diseño del código existente
Refactoring - Mejorando el diseño del código existente
 
Introduction To Groovy
Introduction To GroovyIntroduction To Groovy
Introduction To Groovy
 

Mehr von Stéphane Maldini

Multi-service reactive streams using Spring, Reactor, RSocket
Multi-service reactive streams using Spring, Reactor, RSocketMulti-service reactive streams using Spring, Reactor, RSocket
Multi-service reactive streams using Spring, Reactor, RSocketStéphane Maldini
 
The Future of Reactive Architectures
The Future of Reactive ArchitecturesThe Future of Reactive Architectures
The Future of Reactive ArchitecturesStéphane Maldini
 
What's new in Reactor Californium
What's new in Reactor CaliforniumWhat's new in Reactor Californium
What's new in Reactor CaliforniumStéphane Maldini
 
Spring boot 2.0 reactive bits (June 2018)
Spring boot 2.0 reactive bits (June 2018)Spring boot 2.0 reactive bits (June 2018)
Spring boot 2.0 reactive bits (June 2018)Stéphane Maldini
 
Introduction to Reactive Streams and Reactor 2.5
Introduction to Reactive Streams and Reactor 2.5Introduction to Reactive Streams and Reactor 2.5
Introduction to Reactive Streams and Reactor 2.5Stéphane Maldini
 
Intro to Reactive Programming
Intro to Reactive ProgrammingIntro to Reactive Programming
Intro to Reactive ProgrammingStéphane Maldini
 
Reactor, Reactive streams and MicroServices
Reactor, Reactive streams and MicroServicesReactor, Reactive streams and MicroServices
Reactor, Reactive streams and MicroServicesStéphane Maldini
 

Mehr von Stéphane Maldini (10)

The value of reactive
The value of reactiveThe value of reactive
The value of reactive
 
Multi-service reactive streams using Spring, Reactor, RSocket
Multi-service reactive streams using Spring, Reactor, RSocketMulti-service reactive streams using Spring, Reactor, RSocket
Multi-service reactive streams using Spring, Reactor, RSocket
 
The Future of Reactive Architectures
The Future of Reactive ArchitecturesThe Future of Reactive Architectures
The Future of Reactive Architectures
 
Spring Cloud Gateway
Spring Cloud GatewaySpring Cloud Gateway
Spring Cloud Gateway
 
What's new in Reactor Californium
What's new in Reactor CaliforniumWhat's new in Reactor Californium
What's new in Reactor Californium
 
Spring boot 2.0 reactive bits (June 2018)
Spring boot 2.0 reactive bits (June 2018)Spring boot 2.0 reactive bits (June 2018)
Spring boot 2.0 reactive bits (June 2018)
 
Introduction to Reactive Streams and Reactor 2.5
Introduction to Reactive Streams and Reactor 2.5Introduction to Reactive Streams and Reactor 2.5
Introduction to Reactive Streams and Reactor 2.5
 
Intro to Reactive Programming
Intro to Reactive ProgrammingIntro to Reactive Programming
Intro to Reactive Programming
 
Reactor, Reactive streams and MicroServices
Reactor, Reactive streams and MicroServicesReactor, Reactive streams and MicroServices
Reactor, Reactive streams and MicroServices
 
Eventsggx
EventsggxEventsggx
Eventsggx
 

Kürzlich hochgeladen

04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsRoshan Dwivedi
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilV3cube
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 

Kürzlich hochgeladen (20)

04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 

Groovy reactor grails realtime web devoxx 2013

  • 1. Groovy, Reactor, Grails 
 & the realtime web Guillaume Laforge 
 @glaforge ! Stéphane Maldini
 @smaldini !
  • 2. Stéphane Maldini Consultant and Reactor committer at . ! @smaldini
  • 5.
  • 7.
  • 9.
  • 10. Realtime web applications are about the « now »
  • 11.
  • 12. Show users live updates as they come
  • 13. Show users live updates as they come A « push » approach vs a « pull » approach
  • 14. Show users live updates as they come A « push » approach vs a « pull » approach Handle a big volume of events
  • 15. Show users live updates as they come A « push » approach vs a « pull » approach Handle a big volume of events React fast to new events
  • 16. Show users live updates as they come A « push » approach vs a « pull » approach Handle a big volume of events React fast to new events Use promises, events, streams to react fast and stream updates to users as they are ready
  • 17. Show users live updates as they come Avoid blocking and state A « push » approach vs a « pull » approach Handle a big volume of events React fast to new events Use promises, events, streams to react fast and stream updates to users as they are ready
  • 18. Show users live updates as they come Fail gracefully Avoid blocking and state A « push » approach vs a « pull » approach Handle a big volume of events React fast to new events Use promises, events, streams to react fast and stream updates to users as they are ready
  • 19.
  • 22. Groovy… an Open Source 
 alternative language 
 for the JVM
  • 24. Groovy… But also supports 
 static type checking & 
 static compilation
  • 26.
  • 27.
  • 29.
  • 30. Simplify the life of (Java) developers
  • 31.
  • 32. Groovy as a Java superset
  • 33. Groovy as a Java superset It’s so easy to learn!
  • 34.
  • 35.
  • 36.
  • 37. As safe and fast as Java with static type checking & compilation
  • 38. As safe and fast as Java with static type checking & compilation
  • 39.
  • 40. new  MarkupBuilder().html  {          head  {                  title  "The  Script  Bowl"          }   !        body  {                  div(class:  "banner")  {                          p  "Groovy  rocks!"                  }          }   }
  • 41.
  • 42. move  forward  at  3.km/h Expressive, Concise, Readable
  • 43.
  • 44.
  • 45. Speaking of conciseness... A full Spring app in the span of a tweet! @RestController   class  App  {          @RequestMapping("/")          String  home()  {  "Hello  World!"  }   }
  • 46.
  • 48. Great for scripting Fit for Domain-Specific Languages
  • 49. Great for scripting Fit for Domain-Specific Languages Most seamless integration & interoperability wih java!
  • 50. Great for scripting Full-blown reactive applications too! Fit for Domain-Specific Languages Most seamless integration & interoperability wih java!
  • 51.
  • 52. Most Java code is also valid Groovy code!
  • 53. Most Java code is also valid Groovy code! Any Java developer is a Groovy developer!
  • 54.
  • 57. Scripts versus Classes public  class  Main  {          public  static  void  main(String[]  args)  {                  System.out.println("Hello");          }   } vs @glaforge — @smaldini / #DV13-rtweb !26
  • 58. Scripts versus Classes public  class  Main  {          public  static  void  main(String[]  args)  {                  System.out.println("Hello");          }   } vs println  "Hello" @glaforge — @smaldini / #DV13-rtweb !26
  • 65. Optional... public  class  Greeter  {          private  String  owner;   !        public  String  getOwner()  {                  return  owner;          }   !        public  void  setOwner(String  owner)  {                  this.owner  =  owner;          }   !        public  String  greet(String  name)  {                  return  "Hello  "  +  name  +  ",  I  am  "  +  owner;          }   }   ! Greeter  greeter  =  new  Greeter();   greeter.setOwner("Guillaume");   ! System.out.println(greeter.greet("Marion")); @glaforge — @smaldini / #DV13-rtweb !28
  • 66. Optional... Semicolons public  class  Greeter  {          private  String  owner;   !        public  String  getOwner()  {                  return  owner;          }   !        public  void  setOwner(String  owner)  {                  this.owner  =  owner;          }   !        public  String  greet(String  name)  {                  return  "Hello  "  +  name  +  ",  I  am  "  +  owner;          }   }   ! Greeter  greeter  =  new  Greeter();   greeter.setOwner("Guillaume");   ! System.out.println(greeter.greet("Marion")); @glaforge — @smaldini / #DV13-rtweb !28
  • 67. Optional... public  class  Greeter  {          private  String  owner   !        public  String  getOwner()  {                  return  owner          }   !        public  void  setOwner(String  owner)  {                  this.owner  =  owner          }   !        public  String  greet(String  name)  {                  return  "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! Greeter  greeter  =  new  Greeter()   greeter.setOwner("Guillaume")   ! System.out.println(greeter.greet("Marion")) @glaforge — @smaldini / #DV13-rtweb !29
  • 68. Optional... public  class  Greeter  {          private  String  owner   !        public  String  getOwner()  {                  return  owner          }   !        public  void  setOwner(String  owner)  {                  this.owner  =  owner          }   !        public  String  greet(String  name)  {                  return  "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! Greeter  greeter  =  new  Greeter()   greeter.setOwner("Guillaume")   ! System.out.println(greeter.greet("Marion")) @glaforge — @smaldini / #DV13-rtweb !30
  • 69. Optional... public  class  Greeter  {          private  String  owner   !        public  String  getOwner()  {                  return  owner          }   !        public  void  setOwner(String  owner)  {                  this.owner  =  owner          }   !        public  String  greet(String  name)  {                  return  "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! Greeter  greeter  =  new  Greeter()   greeter.setOwner("Guillaume")   Parentheses ! System.out.println(greeter.greet("Marion")) @glaforge — @smaldini / #DV13-rtweb !30
  • 70. Optional... public  class  Greeter  {          private  String  owner   !        public  String  getOwner()  {                  return  owner          }   !        public  void  setOwner(String  owner)  {                  this.owner  =  owner          }   !        public  String  greet(String  name)  {                  return  "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! Greeter  greeter  =  new  Greeter()   greeter.setOwner  "Guillaume"   ! System.out.println  greeter.greet("Marion") @glaforge — @smaldini / #DV13-rtweb !31
  • 71. Optional... public  class  Greeter  {          private  String  owner   !        public  String  getOwner()  {                  return  owner          }   !        public  void  setOwner(String  owner)  {                  this.owner  =  owner          }   ! return keyword        public  String  greet(String  name)  {                  return  "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! Greeter  greeter  =  new  Greeter()   greeter.setOwner  "Guillaume"   ! System.out.println  greeter.greet("Marion") @glaforge — @smaldini / #DV13-rtweb !31
  • 72. Optional... public  class  Greeter  {          private  String  owner   !        public  String  getOwner()  {                                owner          }   !        public  void  setOwner(String  owner)  {                  this.owner  =  owner          }   !        public  String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! Greeter  greeter  =  new  Greeter()   greeter.setOwner  "Guillaume"   ! System.out.println  greeter.greet("Marion") @glaforge — @smaldini / #DV13-rtweb !32
  • 73. Optional... public  class  Greeter  {          private  String  owner   !        public  String  getOwner()  {                                owner          }   ! public keyword        public  void  setOwner(String  owner)  {                  this.owner  =  owner          }   !        public  String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! Greeter  greeter  =  new  Greeter()   greeter.setOwner  "Guillaume"   ! System.out.println  greeter.greet("Marion") @glaforge — @smaldini / #DV13-rtweb !32
  • 74. Optional...              class  Greeter  {          private  String  owner   !                      String  getOwner()  {                                owner          }   !                      void  setOwner(String  owner)  {                  this.owner  =  owner          }   !                      String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! Greeter  greeter  =  new  Greeter()   greeter.setOwner  "Guillaume"   ! System.out.println  greeter.greet("Marion") @glaforge — @smaldini / #DV13-rtweb !33
  • 75. Optional...              class  Greeter  {          private  String  owner   !                      String  getOwner()  {                                owner          }   !                      void  setOwner(String  owner)  {                  this.owner  =  owner          }   !                      String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   optional typing ! Greeter  greeter  =  new  Greeter()   greeter.setOwner  "Guillaume"   ! System.out.println  greeter.greet("Marion") @glaforge — @smaldini / #DV13-rtweb !33
  • 76. Optional...              class  Greeter  {          private  String  owner   !                      String  getOwner()  {                                owner          }   !                      void  setOwner(String  owner)  {                  this.owner  =  owner          }   !                      String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! def          greeter  =  new  Greeter()   greeter.setOwner  "Guillaume"   ! System.out.println  greeter.greet("Marion") @glaforge — @smaldini / #DV13-rtweb !34
  • 77. Optional...              class  Greeter  {          private  String  owner   !                      String  getOwner()  {                                owner          }   !                      void  setOwner(String  owner)  {                  this.owner  =  owner          }   !                      String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   handy println shortcut def          greeter  =  new  Greeter()   ! greeter.setOwner  "Guillaume"   ! System.out.println  greeter.greet("Marion") @glaforge — @smaldini / #DV13-rtweb !34
  • 78. Optional...              class  Greeter  {          private  String  owner   !                      String  getOwner()  {                                owner          }   !                      void  setOwner(String  owner)  {                  this.owner  =  owner          }   !                      String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! def          greeter  =  new  Greeter()   greeter.setOwner  "Guillaume"   !                      println  greeter.greet("Marion") @glaforge — @smaldini / #DV13-rtweb !35
  • 79. Optional... verbose Java properties!              class  Greeter  {          private  String  owner   !                      String  getOwner()  {                                owner          }   !                      void  setOwner(String  owner)  {                  this.owner  =  owner          }   !                      String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! def          greeter  =  new  Greeter()   greeter.setOwner  "Guillaume"   !                      println  greeter.greet("Marion") @glaforge — @smaldini / #DV13-rtweb !35
  • 80. Optional...              class  Greeter  {                          String  owner   ! ! ! ! ! ! ! ! !                      String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! def          greeter  =  new  Greeter()   greeter.setOwner  "Guillaume"   !                      println  greeter.greet("Marion") @glaforge — @smaldini / #DV13-rtweb !36
  • 81. Optional...              class  Greeter  {                          String  owner   ! ! ! ! ! ! ! ! !                      String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! Property notation def          greeter  =  new  Greeter()   greeter.setOwner  "Guillaume"   !                      println  greeter.greet("Marion") @glaforge — @smaldini / #DV13-rtweb !36
  • 82. Optional...              class  Greeter  {                          String  owner   ! ! ! ! ! ! ! ! !                      String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! def          greeter  =  new  Greeter()   greeter.owner  =    "Guillaume"   !                      println  greeter.greet("Marion") @glaforge — @smaldini / #DV13-rtweb !37
  • 83. Optional...              class  Greeter  {                          String  owner   ! ! ! ! ! ! ! ! Named argument                      String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner   constructor !        }   }   ! def          greeter  =  new  Greeter()   greeter.owner  =    "Guillaume"   !                      println  greeter.greet("Marion") @glaforge — @smaldini / #DV13-rtweb !37
  • 84. Optional...              class  Greeter  {                          String  owner   ! ! ! ! ! ! ! ! !                      String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! def          greeter  =  new  Greeter(owner:  "Guillaume")   ! !                      println  greeter.greet("Marion") @glaforge — @smaldini / #DV13-rtweb !38
  • 85. Optional...              class  Greeter  {                          String  owner   ! ! ! ! ! ! Interpolated strings! (aka GStrings) ! ! !                      String  greet(String  name)  {                                "Hello  "  +  name  +  ",  I  am  "  +  owner          }   }   ! def          greeter  =  new  Greeter(owner:  "Guillaume")   ! !                      println  greeter.greet("Marion") @glaforge — @smaldini / #DV13-rtweb !38
  • 86. Optional...              class  Greeter  {                          String  owner   ! ! ! ! ! ! ! ! !                      String  greet(String  name)  {                                "Hello  ${name},  I  am  ${owner}"          }   }   ! def          greeter  =  new  Greeter(owner:  "Guillaume")   ! !                      println  greeter.greet("Marion") @glaforge — @smaldini / #DV13-rtweb !39
  • 87. Optional...              class  Greeter  {                          String  owner   ! ! ! ! Let’s reformat that mess of whitespace! ! ! ! ! !                      String  greet(String  name)  {                                "Hello  ${name},  I  am  ${owner}"          }   }   ! def          greeter  =  new  Greeter(owner:  "Guillaume")   ! !                      println  greeter.greet("Marion") @glaforge — @smaldini / #DV13-rtweb !39
  • 88. Optional... class  Greeter  {          String  owner   !        String  greet(String  name)  {                "Hello  ${name},  I  am  ${owner}"          }   }   ! def  greeter  =  new  Greeter(owner:  "Guillaume")   ! println  greeter.greet("Marion") @glaforge — @smaldini / #DV13-rtweb !40
  • 89. Optional... public  class  Greeter  {          private  String  owner;   !        public  String  getOwner()  {   class  Greeter  {                  return  owner;          String  owner          }   ! !        String  greet(String  name)  {          public  void  setOwner(String  owner)  {                "Hello  ${name},  I  am  ${owner}"                  this.owner  =  owner;          }          }   }   ! !        public  String  greet(String  name)  {   def  greeter  =  new  Greeter(owner:  "Guillaume")                  return  "Hello  "  +  name  +  ",  I  am  "  +  owner;   !        }   println  greeter.greet("Marion") }   ! Greeter  greeter  =  new  Greeter();   greeter.setOwner("Guillaume");   ! System.out.println(greeter.greet("Marion")); @glaforge — @smaldini / #DV13-rtweb !40
  • 90. Optional... class  Greeter  {          String  owner   !        String  greet(String  name)  {                "Hello  ${name},  I  am  ${owner}"          }   }   ! def  greeter  =  new  Greeter(owner:  "Guillaume")   ! println  greeter.greet("Marion") @glaforge — @smaldini / #DV13-rtweb !40
  • 91. Native syntax constructs //  closures   def  adder  =  {  a,  b  -­‐>  a  +  b  }   ! //  lists   def  list  =  [1,  2,  3,  4,  5]   ! //  maps   def  map  =  [a:  1,  b:  2,  c:  3]   ! //  regular  expressions   def  regex  =  ~/.*foo.*/   ! //  ranges   def  range  128..255 @glaforge — @smaldini / #DV13-rtweb !41
  • 92. Closures — the basics • Functions as first-class citizen of the language def  adder  =  {  a,  b  -­‐>  a  +  b  }   ! assert  adder(1,  2)  ==  3   assert  adder('a',  'b')  ==  'ab' @glaforge — @smaldini / #DV13-rtweb !42
  • 93. Closures — the basics • Functions as first-class citizen of the language Closure parameters def  adder  =  {  a,  b  -­‐>  a  +  b  }   ! assert  adder(1,  2)  ==  3   assert  adder('a',  'b')  ==  'ab' @glaforge — @smaldini / #DV13-rtweb !42
  • 94. Closures — the basics • Functions as first-class citizen of the language Assign a function Closure into a variable parameters def  adder  =  {  a,  b  -­‐>  a  +  b  }   ! assert  adder(1,  2)  ==  3   assert  adder('a',  'b')  ==  'ab' @glaforge — @smaldini / #DV13-rtweb !42
  • 95. Closures — the basics • Functions as first-class citizen of the language Assign a function Closure into a variable parameters def  adder  =  {  a,  b  -­‐>  a  +  b  }   ! assert  adder(1,  2)  ==  3   assert  adder('a',  'b')  ==  'ab' Short form of: adder.call(‘a’, ‘b’) @glaforge — @smaldini / #DV13-rtweb !42
  • 96. Closures — the basics • Functions as first-class citizen of the language Assign a function Closure into a variable parameters def  adder  =  {  a,  b  -­‐>  a  +  b  }   ! assert  adder(1,  2)  ==  3   assert  adder('a',  'b')  ==  'ab' Short form of: adder.call(‘a’, ‘b’) @glaforge — @smaldini / #DV13-rtweb Genericity with duck typing & operator overloading !42
  • 97. Closures — explicit type ! def  intAdder  =  {  int  a,  int  b  -­‐>  a  +  b  } @glaforge — @smaldini / #DV13-rtweb !43
  • 98. Closures — explicit type Be explicit about the types ! def  intAdder  =  {  int  a,  int  b  -­‐>  a  +  b  } @glaforge — @smaldini / #DV13-rtweb !43
  • 99. Closures — implicit parameter def  doubler  =  {  it  *  2  }   ! assert  doubler(3)  ==  6   assert  doubler('a')  ==  'aa' @glaforge — @smaldini / #DV13-rtweb !44
  • 100. Closures — implicit parameter Implicit parameter def  doubler  =  {  it  *  2  }   ! assert  doubler(3)  ==  6   assert  doubler('a')  ==  'aa' @glaforge — @smaldini / #DV13-rtweb !44
  • 101. Closures — implicit parameter Implicit parameter def  doubler  =  {  it  *  2  }   ! assert  doubler(3)  ==  6   assert  doubler('a')  ==  'aa' Multiply also defined on strings @glaforge — @smaldini / #DV13-rtweb !44
  • 102. Closures — variable arguments def  sum  =  {  ...  elements  -­‐>  
                                elements.sum()  }   ! assert  sum(1,  2)  ==  3   assert  sum('a',  'b',  'c')  ==  'abc' @glaforge — @smaldini / #DV13-rtweb !45
  • 103. Closures — variable arguments Variable number of arguments def  sum  =  {  ...  elements  -­‐>  
                                elements.sum()  }   ! assert  sum(1,  2)  ==  3   assert  sum('a',  'b',  'c')  ==  'abc' @glaforge — @smaldini / #DV13-rtweb !45
  • 104. Closures — variable arguments You can specify the type: int... Variable number of arguments def  sum  =  {  ...  elements  -­‐>  
                                elements.sum()  }   ! assert  sum(1,  2)  ==  3   assert  sum('a',  'b',  'c')  ==  'abc' @glaforge — @smaldini / #DV13-rtweb !45
  • 105. Closures — default values def  mult  =  {  int  a,  int  b  =  10  -­‐>  a  *  b  }   ! assert  mult(2,  3)  ==  6   assert  mult(5)  ==  50 @glaforge — @smaldini / #DV13-rtweb !46
  • 106. Closures — default values Default value def  mult  =  {  int  a,  int  b  =  10  -­‐>  a  *  b  }   ! assert  mult(2,  3)  ==  6   assert  mult(5)  ==  50 @glaforge — @smaldini / #DV13-rtweb !46
  • 107. Closures — default values Default value def  mult  =  {  int  a,  int  b  =  10  -­‐>  a  *  b  }   ! assert  mult(2,  3)  ==  6   assert  mult(5)  ==  50 @glaforge — @smaldini / #DV13-rtweb Provided value for b !46
  • 108. Closures — default values Default value def  mult  =  {  int  a,  int  b  =  10  -­‐>  a  *  b  }   ! assert  mult(2,  3)  ==  6   assert  mult(5)  ==  50 Default value used for b @glaforge — @smaldini / #DV13-rtweb Provided value for b !46
  • 109. Closures — methods as functions def  logBase10  =  Math.&log10   def  printer  =  System.out.&println   ! assert  logBase10(10)  ==  1   printer  'abc' @glaforge — @smaldini / #DV13-rtweb !47
  • 110. Closures — methods as functions Turn a method into a closure function def  logBase10  =  Math.&log10   def  printer  =  System.out.&println   ! assert  logBase10(10)  ==  1   printer  'abc' @glaforge — @smaldini / #DV13-rtweb !47
  • 111. Closures — map / filter / reduce @glaforge — @smaldini / #DV13-rtweb !48
  • 112. Closures — map / filter / reduce @groovy.transform.Immutable
 class  Person  {
        String  name
        int  age
 } @glaforge — @smaldini / #DV13-rtweb !48
  • 113. Closures — map / filter / reduce @groovy.transform.Immutable
 class  Person  {
        String  name
        int  age
 } @glaforge — @smaldini / #DV13-rtweb !48
  • 114. Closures — map / filter / reduce @groovy.transform.Immutable
 class  Person  {
        String  name
        int  age
 } def  persons  =  [
        new  Person('Guillaume',  36),
        new  Person('Marion',  5),
        new  Person('Erine',  1)
 ] @glaforge — @smaldini / #DV13-rtweb !48
  • 115. Closures — map / filter / reduce @groovy.transform.Immutable
 class  Person  {
        String  name
        int  age
 } def  persons  =  [
        new  Person('Guillaume',  36),
        new  Person('Marion',  5),
        new  Person('Erine',  1)
 ] @glaforge — @smaldini / #DV13-rtweb !48
  • 116. Closures — map / filter / reduce @groovy.transform.Immutable
 class  Person  {
        String  name
        int  age
 } def  persons  =  [
        new  Person('Guillaume',  36),
        new  Person('Marion',  5),
        new  Person('Erine',  1)
 ] def  names  =
        persons.findAll  {  it.age  <  18  }
                      .collect  {  it.name.toUpperCase()  }
                      .sort()
                      .join(',  ') @glaforge — @smaldini / #DV13-rtweb !48
  • 117. Closures — map / filter / reduce @groovy.transform.Immutable
 class  Person  {
        String  name
        int  age
 } def  persons  =  [
        new  Person('Guillaume',  36),
        new  Person('Marion',  5),
        new  Person('Erine',  1)
 ] def  names  =
        persons.findAll  {  it.age  <  18  }
                      .collect  {  it.name.toUpperCase()  }
                      .sort()
                      .join(',  ') @glaforge — @smaldini / #DV13-rtweb !48
  • 118. Closures — map / filter / reduce @groovy.transform.Immutable
 class  Person  {
        String  name
        int  age
 } def  persons  =  [
        new  Person('Guillaume',  36),
        new  Person('Marion',  5),
        new  Person('Erine',  1)
 ] def  names  =
        persons.findAll  {  it.age  <  18  }
                      .collect  {  it.name.toUpperCase()  }
                      .sort()
                      .join(',  ') assert  names  ==  "ERINE,  MARION" @glaforge — @smaldini / #DV13-rtweb !48
  • 119. Closures — map / filter / reduce @groovy.transform.Immutable
 class  Person  {
        String  name
        int  age
 } def  persons  =  [
        new  Person('Guillaume',  36),
        new  Person('Marion',  5),
        new  Person('Erine',  1)
 ] find/findAll, inject, collect, flatten, min/max, unique, reverse, collate, groupBy, any/every, head/tail/last, count/countBy, combinations/ permutations/subsequences/ transpose, withDefault/ withLazyDefault def  names  =
        persons.findAll  {  it.age  <  18  }
                      .collect  {  it.name.toUpperCase()  }
                      .sort()
                      .join(',  ') assert  names  ==  "ERINE,  MARION" @glaforge — @smaldini / #DV13-rtweb !48
  • 120. Closures — resource handling new  File('bible.txt').withReader  {  r  -­‐>          new  File('out.txt').withWriter  {  w  -­‐>                  r.eachLine  {  line  -­‐>                          if  (line.contains('Groovy'))                                  w  <<  line.toUpperCase()                  }          }   } @glaforge — @smaldini / #DV13-rtweb !49
  • 121. Closures — resource handling Take care of properly opening / closing resources new  File('bible.txt').withReader  {  r  -­‐>          new  File('out.txt').withWriter  {  w  -­‐>                  r.eachLine  {  line  -­‐>                          if  (line.contains('Groovy'))                                  w  <<  line.toUpperCase()                  }          }   } @glaforge — @smaldini / #DV13-rtweb !49
  • 122. Closures — custom control structures void  unless(boolean  cond,  Closure  c)  {          if  (!cond)  c()   }   ! unless  (10  <  9)  {          println  "less"   } @glaforge — @smaldini / #DV13-rtweb !50
  • 123. Closures — custom control structures Closure as last argument void  unless(boolean  cond,  Closure  c)  {          if  (!cond)  c()   }   ! unless  (10  <  9)  {          println  "less"   } @glaforge — @smaldini / #DV13-rtweb !50
  • 124. Closures — custom control structures Closure as last argument void  unless(boolean  cond,  Closure  c)  {          if  (!cond)  c()   }   ! unless  (10  <  9)  {          println  "less"   } @glaforge — @smaldini / #DV13-rtweb Equivalent to: unless(10<9, {...}) !50
  • 125. Closures — custom control structures class  Reactor  {            void  on(Selector  s,  Closure  c)  {  …  }   }   …   reactor.on(  $(‘abc')  )  {  Event<String>  ev  -­‐>          …   } @glaforge — @smaldini / #DV13-rtweb !51
  • 126. Closures — builders leverage closures import  groovy.json.*   ! def  json  =  new  JsonBuilder()   json.person  {          name  'Guillaume'          age  36          daughters  'Marion',  'Erine'          address  {                  street  '1  Main  Street'                  zip  75001                  city  'Paris'          }   } @glaforge — @smaldini / #DV13-rtweb !52
  • 127. Closures — builders leverage closures import  groovy.json.*   ! def  json  =  new  JsonBuilder()   json.person  {          name  'Guillaume'          age  36          daughters  'Marion',  'Erine'          address  {                  street  '1  Main  Street'                  zip  75001                  city  'Paris'          }   } @glaforge — @smaldini / #DV13-rtweb Hierarchical data representation !52
  • 128. Closures — builders leverage closures import  groovy.json.*   ! Hierarchical data representation def  json  =  new  JsonBuilder()   json.person  {          name  'Guillaume'          age  36   Closure blocks        daughters  'Marion',  'Erine'   delimiting the        address  {   structure                street  '1  Main  Street'                  zip  75001                  city  'Paris'          }   } @glaforge — @smaldini / #DV13-rtweb !52
  • 129. Closures — builders leverage closures import  groovy.json.*   {          "person":  {   Hierarchical data def  json  =  new  JsonBuilder()                  "name":  "Guillaume",   representation                "age":  36,   json.person  {                  "daughters":  [          name  'Guillaume'                          "Marion",                          "Erine"          age  36                  ],   Closure blocks        daughters  'Marion',  'Erine'                  "address":  {   delimiting the                        "street":  "1  Main  Street",          address  {                          "zip":  75001,   structure                street  '1  Main  Street'                          "city":  "Paris"                  }                  zip  75001          }                  city  'Paris'   } !        }   } @glaforge — @smaldini / #DV13-rtweb !52
  • 130. Closure — your own builders GroovyEnvironment.create  {          environment  {                  defaultDispatcher  =  "test"   !                dispatcher('test')  {                          type  =  DispatcherType.SYNCHRONOUS                  }          }   } @glaforge — @smaldini / #DV13-rtweb !53
  • 131. Closure — your own builders GroovyEnvironment.create  {          environment  {                  defaultDispatcher  =  "test"   !                dispatcher('test')  {                          type  =  DispatcherType.SYNCHRONOUS                  }          }   } @glaforge — @smaldini / #DV13-rtweb !53
  • 132. Closure — your own builders GroovyEnvironment.create  {          environment  {                  defaultDispatcher  =  "test"   !                dispatcher('test')  {                          type  =  DispatcherType.SYNCHRONOUS                  }          }   } @glaforge — @smaldini / #DV13-rtweb !53
  • 133. Closure — your own builders GroovyEnvironment.create  {          environment  {                  defaultDispatcher  =  "test"   !                dispatcher('test')  {                          type  =  DispatcherType.SYNCHRONOUS                  }          }   } @glaforge — @smaldini / #DV13-rtweb !53
  • 134. Closure — your own builders GroovyEnvironment.create  {          environment  {                  defaultDispatcher  =  "test"   !                dispatcher('test')  {                          type  =  DispatcherType.SYNCHRONOUS                  }          }   } @glaforge — @smaldini / #DV13-rtweb !53
  • 135. Closure — your own builders Implement a builder extending BuilderSupport or FactoryBuilderSupport… GroovyEnvironment.create  {   or roll your own!        environment  {                  defaultDispatcher  =  "test"   !                dispatcher('test')  {                          type  =  DispatcherType.SYNCHRONOUS                  }          }   } @glaforge — @smaldini / #DV13-rtweb !53
  • 136. Closure — your own builders Implement a builder extending BuilderSupport or FactoryBuilderSupport… GroovyEnvironment.create  {   or roll your own!        environment  {                  defaultDispatcher  =  "test"   abstract  class  BuilderSupport  {          abstract  void  setParent(Object  parent,  Object  child)   !        abstract  Object  createNode(Object  name)                  dispatcher('test')  {          abstract  Object  createNode(Object  name,  Object  value)          abstract  Object  createNode(Object  name,  Map  attributes)                          type  =  DispatcherType.SYNCHRONOUS          abstract  Object  createNode(Object  name,  Map  attributes,  Object  value)   }                  }          }   } @glaforge — @smaldini / #DV13-rtweb !53
  • 137. GPath expressions • GPath expressions are like XPath 
 but for an object graph import  groovy.json.*   ! def  url  =  "https://api.github.com/repos/groovy/groovy-­‐core/commits"   ! def  commits  =  new  JsonSlurper().parseText(url.toURL().text)   ! assert  commits[0].commit.author.name  ==  'Cedric  Champeau' @glaforge — @smaldini / #DV13-rtweb !54
  • 138. GPath expressions • GPath expressions are like XPath 
 but for an object graph import  groovy.json.*   ! def  url  =  "https://api.github.com/repos/groovy/groovy-­‐core/commits"   ! def  commits  =  new  JsonSlurper().parseText(url.toURL().text)   ! assert  commits[0].commit.author.name  ==  'Cedric  Champeau' GPath expression @glaforge — @smaldini / #DV13-rtweb !54
  • 139. GPath expressions • GPath expressions are like XPath 
 but for an object graph import  groovy.json.*   ! def  url  =  "https://api.github.com/repos/groovy/groovy-­‐core/commits"   ! def  commits  =  new  JsonSlurper().parseText(url.toURL().text)   ! assert  commits[0].commit.author.name  ==  'Cedric  Champeau' GPath expression @glaforge — @smaldini / #DV13-rtweb Add find / findAll into the mix !54
  • 140. GPath expressions • GPath expressions are like XPath 
 but for an object graph No (un)marshalling! import  groovy.json.*   ! def  url  =  "https://api.github.com/repos/groovy/groovy-­‐core/commits"   ! def  commits  =  new  JsonSlurper().parseText(url.toURL().text)   ! assert  commits[0].commit.author.name  ==  'Cedric  Champeau' GPath expression @glaforge — @smaldini / #DV13-rtweb Add find / findAll into the mix !54
  • 141. Lists def  list  =  ['a',  'b',  'c']   ! list  <<  'd'   assert  list.contains('d')   ! assert  list.findAll  {  it.startsWith  'a'  }.size()  ==  1   assert  list.collect  {  it.toUpperCase()  }  
                                                              ==  ['A',  'B',  'C',  'D']   assert  list.inject('')  {  a,  b  -­‐>  a  +  b  }  ==  'abcd' @glaforge — @smaldini / #DV13-rtweb !55
  • 142. Lists List definition def  list  =  ['a',  'b',  'c']   ! list  <<  'd'   assert  list.contains('d')   ! assert  list.findAll  {  it.startsWith  'a'  }.size()  ==  1   assert  list.collect  {  it.toUpperCase()  }  
                                                              ==  ['A',  'B',  'C',  'D']   assert  list.inject('')  {  a,  b  -­‐>  a  +  b  }  ==  'abcd' @glaforge — @smaldini / #DV13-rtweb !55
  • 143. Lists List definition def  list  =  ['a',  'b',  'c']   ! list  <<  'd'   assert  list.contains('d')   Append an element (operator overloading) ! assert  list.findAll  {  it.startsWith  'a'  }.size()  ==  1   assert  list.collect  {  it.toUpperCase()  }  
                                                              ==  ['A',  'B',  'C',  'D']   assert  list.inject('')  {  a,  b  -­‐>  a  +  b  }  ==  'abcd' @glaforge — @smaldini / #DV13-rtweb !55
  • 144. Lists List definition def  list  =  ['a',  'b',  'c']   ! list  <<  'd'   assert  list.contains('d')   Append an element (operator overloading) ! assert  list.findAll  {  it.startsWith  'a'  }.size()  ==  1   assert  list.collect  {  it.toUpperCase()  }  
                                                              ==  ['A',  'B',  'C',  'D']   assert  list.inject('')  {  a,  b  -­‐>  a  +  b  }  ==  'abcd' Functional-style map / filter / reduce with closures @glaforge — @smaldini / #DV13-rtweb !55
  • 145. Maps def  map  =  [name:  'Guillaume',  age:  36]   ! map.daughters  =  ['Marion',  'Erine']   ! assert  map['daughters'].contains('Marion') @glaforge — @smaldini / #DV13-rtweb !56
  • 146. Maps Map definition def  map  =  [name:  'Guillaume',  age:  36]   ! map.daughters  =  ['Marion',  'Erine']   ! assert  map['daughters'].contains('Marion') @glaforge — @smaldini / #DV13-rtweb !56
  • 147. Maps Map definition def  map  =  [name:  'Guillaume',  age:  36]   ! map.daughters  =  ['Marion',  'Erine']   ! assert  map['daughters'].contains('Marion') Indexed access @glaforge — @smaldini / #DV13-rtweb !56
  • 148. Maps Map definition def  map  =  [name:  'Guillaume',  age:  36]   ! map.daughters  =  ['Marion',  'Erine']   ! assert  map['daughters'].contains('Marion') Property notation access @glaforge — @smaldini / #DV13-rtweb Indexed access !56
  • 149. Regular expressions def  pattern  =  ~/.*foo.*/   ! assert  "Alibaba"  ==~  /.*(ba){2}/   ! def  matcher  =  "Superman"  =~  /([A-­‐Z][a-­‐z]+)man/   assert  matcher[0][0]  ==  'Superman'   assert  matcher[0][1]  ==  'Super'   ! '75001  Paris'.find(/(d{5})s(w+)/)  {  match,  zip,  town  -­‐>          println  "The  Zip  code  of  ${town}  is  ${zip}"   } @glaforge — @smaldini / #DV13-rtweb !57
  • 150. Regular expressions Pattern def  pattern  =  ~/.*foo.*/   ! assert  "Alibaba"  ==~  /.*(ba){2}/   ! def  matcher  =  "Superman"  =~  /([A-­‐Z][a-­‐z]+)man/   assert  matcher[0][0]  ==  'Superman'   assert  matcher[0][1]  ==  'Super'   ! '75001  Paris'.find(/(d{5})s(w+)/)  {  match,  zip,  town  -­‐>          println  "The  Zip  code  of  ${town}  is  ${zip}"   } @glaforge — @smaldini / #DV13-rtweb !57
  • 151. Regular expressions Pattern def  pattern  =  ~/.*foo.*/   Match ! assert  "Alibaba"  ==~  /.*(ba){2}/   ! def  matcher  =  "Superman"  =~  /([A-­‐Z][a-­‐z]+)man/   assert  matcher[0][0]  ==  'Superman'   assert  matcher[0][1]  ==  'Super'   ! '75001  Paris'.find(/(d{5})s(w+)/)  {  match,  zip,  town  -­‐>          println  "The  Zip  code  of  ${town}  is  ${zip}"   } @glaforge — @smaldini / #DV13-rtweb !57
  • 152. Regular expressions Pattern def  pattern  =  ~/.*foo.*/   Match ! assert  "Alibaba"  ==~  /.*(ba){2}/   Find ! def  matcher  =  "Superman"  =~  /([A-­‐Z][a-­‐z]+)man/   assert  matcher[0][0]  ==  'Superman'   assert  matcher[0][1]  ==  'Super'   ! '75001  Paris'.find(/(d{5})s(w+)/)  {  match,  zip,  town  -­‐>          println  "The  Zip  code  of  ${town}  is  ${zip}"   } @glaforge — @smaldini / #DV13-rtweb !57
  • 153. Regular expressions Pattern def  pattern  =  ~/.*foo.*/   Match ! assert  "Alibaba"  ==~  /.*(ba){2}/   Find ! def  matcher  =  "Superman"  =~  /([A-­‐Z][a-­‐z]+)man/   assert  matcher[0][0]  ==  'Superman'   assert  matcher[0][1]  ==  'Super'   ! '75001  Paris'.find(/(d{5})s(w+)/)  {  match,  zip,  town  -­‐>          println  "The  Zip  code  of  ${town}  is  ${zip}"   } Nice way to decompose the matched regions @glaforge — @smaldini / #DV13-rtweb !57
  • 154. Ranges def  range  =  'a'..'z'   ! assert  range.contains('m')   assert  range.contains('z')   ! def  exclusive  =  1..<10   ! assert  !exclusive.contains(10)   ! def  reverse  =  10..0   ! assert  reverse[0]  ==  10   assert  reverse[-­‐1]  ==  0 @glaforge — @smaldini / #DV13-rtweb !58
  • 155. Ranges Range def  range  =  'a'..'z'   ! assert  range.contains('m')   assert  range.contains('z')   ! def  exclusive  =  1..<10   ! assert  !exclusive.contains(10)   ! def  reverse  =  10..0   ! assert  reverse[0]  ==  10   assert  reverse[-­‐1]  ==  0 @glaforge — @smaldini / #DV13-rtweb !58
  • 156. Ranges Range def  range  =  'a'..'z'   ! assert  range.contains('m')   assert  range.contains('z')   ! def  exclusive  =  1..<10   Excluded upper bound ! assert  !exclusive.contains(10)   ! def  reverse  =  10..0   ! assert  reverse[0]  ==  10   assert  reverse[-­‐1]  ==  0 @glaforge — @smaldini / #DV13-rtweb !58
  • 157. Ranges Range def  range  =  'a'..'z'   ! assert  range.contains('m')   assert  range.contains('z')   ! def  exclusive  =  1..<10   Excluded upper bound ! assert  !exclusive.contains(10)   ! def  reverse  =  10..0   Reverse range ! assert  reverse[0]  ==  10   assert  reverse[-­‐1]  ==  0 @glaforge — @smaldini / #DV13-rtweb !58
  • 158. Ranges Range def  range  =  'a'..'z'   ! assert  range.contains('m')   assert  range.contains('z')   ! def  exclusive  =  1..<10   Excluded upper bound ! assert  !exclusive.contains(10)   ! def  reverse  =  10..0   Reverse range ! assert  reverse[0]  ==  10   assert  reverse[-­‐1]  ==  0 @glaforge — @smaldini / #DV13-rtweb Negative index count from the end !58
  • 159. Strings, GStrings, multiline strings def  name  =  'Groovy'   def  tmpl  =  """          Dear  Mr  ${name},          You're  the  winner  of  the  lottery!          Yours  sincerly,          Dave   """   ! assert  tmpl.toString().contains('Groovy') @glaforge — @smaldini / #DV13-rtweb !59
  • 160. Strings, GStrings, multiline strings Plain java.lang.String def  name  =  'Groovy'   def  tmpl  =  """          Dear  Mr  ${name},          You're  the  winner  of  the  lottery!          Yours  sincerly,          Dave   """   ! assert  tmpl.toString().contains('Groovy') @glaforge — @smaldini / #DV13-rtweb !59
  • 161. Strings, GStrings, multiline strings Plain java.lang.String def  name  =  'Groovy'   Multiline string with def  tmpl  =  """   expression interpolation        Dear  Mr  ${name},          You're  the  winner  of  the  lottery!          Yours  sincerly,          Dave   """   ! assert  tmpl.toString().contains('Groovy') @glaforge — @smaldini / #DV13-rtweb !59
  • 162. Surprising numbers... System.out.println(  2.0  -­‐  1.1  ); @glaforge — @smaldini / #DV13-rtweb !60
  • 163. Surprising numbers... System.out.println(  2.0  -­‐  1.1  ); 0.8999999999999999 @glaforge — @smaldini / #DV13-rtweb !60
  • 164. Surprising numbers... System.out.println(  2.0  -­‐  1.1  ); 0.8999999999999999 @glaforge — @smaldini / #DV13-rtweb !60
  • 165. Surprising numbers... System.out.println(  3  /  2  ); @glaforge — @smaldini / #DV13-rtweb !61
  • 166. Surprising numbers... System.out.println(  3  /  2  ); 1 @glaforge — @smaldini / #DV13-rtweb !61
  • 167. Surprising numbers... System.out.println(  3  /  2  ); 1 @glaforge — @smaldini / #DV13-rtweb !61
  • 168. BigDecimal by default! assert  2.0  -­‐  1.1  ==  0.9 assert  3  /  2  ==  1.5 @glaforge — @smaldini / #DV13-rtweb !62
  • 169. BigDecimal by default! assert  2.0  -­‐  1.1  ==  0.9 assert  3  /  2  ==  1.5 One of the reasons why microbenchmarks sometimes showed Groovy to be slow... @glaforge — @smaldini / #DV13-rtweb !62
  • 170. BigDecimal by default! assert  2.0  -­‐  1.1  ==  0.9 assert  3  /  2  ==  1.5 One of the reasons why microbenchmarks sometimes showed Groovy to be slow... @glaforge — @smaldini / #DV13-rtweb But you can use doubles & floats for performance, with ‘d’ or ‘f ’ suffixes or with explicit type !62
  • 171.
  • 172. Powerful switch / case on steroids
  • 173. Powerful switch / case on steroids switch(obj)  {          case  123:                  "number  123";              break          case  "abc":              "string  abc";              break          case  String:            "is  a  string";            break          case  [1,  2,  3]:      "in  list";                    break          case  ~/.*o+.*/:      "regex  match";            break          case  {  it  <  3  }:    "closure  criteria";  break          default:                    "unknown"   }
  • 174. Named arguments move  obj,  x:  3,  y:  4 @glaforge — @smaldini / #DV13-rtweb !64
  • 175. Named arguments move  obj,  x:  3,  y:  4 Normal argument @glaforge — @smaldini / #DV13-rtweb !64
  • 176. Named arguments move  obj,  x:  3,  y:  4 Normal argument @glaforge — @smaldini / #DV13-rtweb Named argument !64
  • 177. Named arguments move  obj,  x:  3,  y:  4 Normal argument Named argument Calls: move(Map m, Object) @glaforge — @smaldini / #DV13-rtweb !64
  • 178. Command chains • Ability to chain method calls without parentheses and dots move  forward  at  3.km/h @glaforge — @smaldini / #DV13-rtweb !65
  • 179. Command chains • Ability to chain method calls without parentheses and dots move  forward  at  3.km/h Actually equivalent to: move(forward).at(3.getKm().div(h)) @glaforge — @smaldini / #DV13-rtweb !65
  • 180. Named arguments & command chains check  that:  vodka  tastes  good @glaforge — @smaldini / #DV13-rtweb !66
  • 181. Named arguments & command chains check  that:  vodka  tastes  good Will call: check(that: vodka).tastes(good) @glaforge — @smaldini / #DV13-rtweb !66
  • 182. Multiple assignment and destructuring def  (a,  b)  =  ['A',  'B']   ! (a,  b)  =  [b,  a]   ! def  (int  i,  int  j)  =  [1,  2]   ! def  geocode(String  place)  {          return  [45.4,  2.3]   }   ! def  (la,  lo)  =  geocode("Paris")   ! assert  la  ==  45.4  &&  lo  ==  2.3 @glaforge — @smaldini / #DV13-rtweb !67
  • 183. Multiple assignment and destructuring def  (a,  b)  =  ['A',  'B']   ! (a,  b)  =  [b,  a]   Classic « swap » ! def  (int  i,  int  j)  =  [1,  2]   ! def  geocode(String  place)  {          return  [45.4,  2.3]   }   ! def  (la,  lo)  =  geocode("Paris")   ! assert  la  ==  45.4  &&  lo  ==  2.3 @glaforge — @smaldini / #DV13-rtweb !67
  • 184. Multiple assignment and destructuring def  (a,  b)  =  ['A',  'B']   ! With types (a,  b)  =  [b,  a]   Classic « swap » ! def  (int  i,  int  j)  =  [1,  2]   ! def  geocode(String  place)  {          return  [45.4,  2.3]   }   ! def  (la,  lo)  =  geocode("Paris")   ! assert  la  ==  45.4  &&  lo  ==  2.3 @glaforge — @smaldini / #DV13-rtweb !67
  • 185. Multiple assignment and destructuring def  (a,  b)  =  ['A',  'B']   ! With types (a,  b)  =  [b,  a]   Classic « swap » ! def  (int  i,  int  j)  =  [1,  2]   ! Method returning a list def  geocode(String  place)  {          return  [45.4,  2.3]   }   ! def  (la,  lo)  =  geocode("Paris")   ! assert  la  ==  45.4  &&  lo  ==  2.3 @glaforge — @smaldini / #DV13-rtweb !67
  • 186. Multiple assignment and destructuring def  (a,  b)  =  ['A',  'B']   ! With types (a,  b)  =  [b,  a]   Classic « swap » ! def  (int  i,  int  j)  =  [1,  2]   ! Method returning a list def  geocode(String  place)  {          return  [45.4,  2.3]   }   Destructuring ! def  (la,  lo)  =  geocode("Paris")   ! assert  la  ==  45.4  &&  lo  ==  2.3 @glaforge — @smaldini / #DV13-rtweb !67
  • 187. Multiple assignment and destructuring class  Point  {          double  x,  y   !        double  getAt(int  idx)  {                  if  (idx  ==  0)  x                  else  if  (idx  ==  1)  y                  else  throw  new  Exception("Wrong  index")          }   }   ! def  (x,  y)  =  new  Point(x:  48.3,  y:  3.5)   ! assert  x  ==  48.3  &&  y  ==  3.5 @glaforge — @smaldini / #DV13-rtweb !68
  • 188. Multiple assignment and destructuring class  Point  {          double  x,  y   Method signature convention: getAt(int) !        double  getAt(int  idx)  {                  if  (idx  ==  0)  x                  else  if  (idx  ==  1)  y                  else  throw  new  Exception("Wrong  index")          }   }   ! def  (x,  y)  =  new  Point(x:  48.3,  y:  3.5)   ! assert  x  ==  48.3  &&  y  ==  3.5 @glaforge — @smaldini / #DV13-rtweb !68
  • 189. Multiple assignment and destructuring class  Point  {          double  x,  y   Method signature convention: getAt(int) !        double  getAt(int  idx)  {                  if  (idx  ==  0)  x                  else  if  (idx  ==  1)  y                  else  throw  new  Exception("Wrong  index")          }   }   Transparent destructuring ! def  (x,  y)  =  new  Point(x:  48.3,  y:  3.5)   ! assert  x  ==  48.3  &&  y  ==  3.5 @glaforge — @smaldini / #DV13-rtweb !68
  • 190. Operator overloading import  static  Unit.*   ! enum  Unit  {      M(1),  KM(1000)   !    double  mult      Unit(double  mult)  {          this.mult  =  mult      }   } @glaforge — @smaldini / #DV13-rtweb !69
  • 191. Operator overloading import  static  Unit.*   ! enum  Unit  {      M(1),  KM(1000)   ! import  groovy.transform.Immutable   import  static  Unit.*      double  mult      Unit(double  mult)  {   !        this.mult  =  mult   @Immutable      }   class  Distance  {   }    double  q      Unit  u   !    Distance  plus(Distance  d)  {          new  Distance(    q  *      u.mult  +  
                                  d.q  *  d.u.mult,  M)      }   } @glaforge — @smaldini / #DV13-rtweb !69
  • 192. Operator overloading import  static  Unit.*   ! import  static  Unit.*   enum  Unit  {      M(1),  KM(1000)   ! def  d10  =  new  Distance(10,  M)   ! import  groovy.transform.Immutable   def  d15  =  new  Distance(15,  M)      double  mult   import  static  Unit.*   !    Unit(double  mult)  {   ! def  d25  =  d10  +  d15          this.mult  =  mult   @Immutable   !    }   class  Distance  {   assert  d25.q  ==  25  &&  d25.u  ==  M }    double  q      Unit  u   !    Distance  plus(Distance  d)  {          new  Distance(    q  *      u.mult  +  
                                  d.q  *  d.u.mult,  M)      }   } @glaforge — @smaldini / #DV13-rtweb !69
  • 193. Operator overloading import  static  Unit.*   ! import  static  Unit.*   enum  Unit  {      M(1),  KM(1000)   ! def  d10  =  new  Distance(10,  M)   ! import  groovy.transform.Immutable   def  d15  =  new  Distance(15,  M)      double  mult   import  static  Unit.*   !    Unit(double  mult)  {   ! def  d25  =  d10  +  d15          this.mult  =  mult   @Immutable   !    }   class  Distance  {   assert  d25.q  ==  25  &&  d25.u  ==  M }    double  q      Unit  u   Overload the ‘+’ operator @glaforge — @smaldini / #DV13-rtweb !    Distance  plus(Distance  d)  {          new  Distance(    q  *      u.mult  +  
                                  d.q  *  d.u.mult,  M)      }   } !69
  • 194. Operator overloading import  static  Unit.*   ! import  static  Unit.*   enum  Unit  {      M(1),  KM(1000)   ! def  d10  =  new  Distance(10,  M)   ! import  groovy.transform.Immutable   def  d15  =  new  Distance(15,  M)      double  mult   import  static  Unit.*   !    Unit(double  mult)  {   ! def  d25  =  d10  +  d15          this.mult  =  mult   @Immutable   !    }   class  Distance  {   assert  d25.q  ==  25  &&  d25.u  ==  M }    double  q      Unit  u   Overload the ‘+’ operator @glaforge — @smaldini / #DV13-rtweb !    Distance  plus(Distance  d)  {          new  Distance(    q  *      u.mult  +  
                                  d.q  *  d.u.mult,  M)      }   } Use ‘+’ !69
  • 195. Operator overloading a  +  b      //  a.plus(b)   a  -­‐  b      //  a.minus(b)   a  *  b      //  a.multiply(b)   a  /  b      //  a.div(b)   a  %  b      //  a.modulo(b)   a  **  b    //  a.power(b)   a  |  b      //  a.or(b)   a  &  b      //  a.and(b)   a  ^  b      //  a.xor(b)   a[b]        //  a.getAt(b)   a  <<  b    //  a.leftShift(b)   a  >>  b    //  a.rightShift(b)   a  >>>  b  //  a.rightShiftUnsigned(b)   +a            //  a.unaryPlus()   -­‐a            //  a.unaryMinus()   ~a            //  a.bitwiseNegate() @glaforge — @smaldini / #DV13-rtweb !70
  • 196. Operator overloading a  +  b      //  a.plus(b)   a  -­‐  b      //  a.minus(b)   a  *  b      //  a.multiply(b)   Operator overloading is a  /  b      //  a.div(b)   a  %  b      //  a.modulo(b)   just a convention on a  **  b    //  a.power(b)   method names a  |  b      //  a.or(b)   a  &  b      //  a.and(b)   a  ^  b      //  a.xor(b)   a[b]        //  a.getAt(b)   a  <<  b    //  a.leftShift(b)   a  >>  b    //  a.rightShift(b)   a  >>>  b  //  a.rightShiftUnsigned(b)   +a            //  a.unaryPlus()   -­‐a            //  a.unaryMinus()   ~a            //  a.bitwiseNegate() @glaforge — @smaldini / #DV13-rtweb !70
  • 197. Power asserts def  (a,  b,  c)  =  [20,  30,  40]   ! assert  a  *  (b  -­‐  1)  /  10  ==  3  *  c  /  2  +  1 @glaforge — @smaldini / #DV13-rtweb !71
  • 198. Power asserts def  (a,  b,  c)  =  [20,  30,  40]   ! assert  a  *  (b  -­‐  1)  /  10  ==  3  *  c  /  2  +  1 Assertion  failed:     ! assert  a  *  (b  -­‐  1)  /  10  ==  3  *  c  /  2  +  1                |  |    |  |        |        |        |  |  |      |                |  580|  29      58      false|  |  60    61                20      30                              |  40                                                            120   !   at  script1.run(script1.groovy:3) @glaforge — @smaldini / #DV13-rtweb !71
  • 199. Power asserts def  (a,  b,  c)  =  [20,  30,  40]   ! assert  a  *  (b  -­‐  1)  /  10  ==  3  *  c  /  2  +  1 Assertion  failed:     ! assert  a  *  (b  -­‐  1)  /  10  ==  3  *  c  /  2  +  1                |  |    |  |        |        |        |  |  |      |                |  580|  29      58      false|  |  60    61                20      30                              |  40                                                            120   ! Invented by the Spock testing framework   at  script1.run(script1.groovy:3) @glaforge — @smaldini / #DV13-rtweb !71
  • 200. Null handling class  Order  {          LineItem  line   }   class  LineItem  {          int  quantity          Item  item   }   class  Item  {          String  name   }   ! def  o  =  new  Order(          line:  new  LineItem(                  quantity:  2,                  item:  null))   ! println  o.line.item.name @glaforge — @smaldini / #DV13-rtweb !72
  • 201. Null handling class  Order  {          LineItem  line   }   class  LineItem  {          int  quantity          Item  item   }   class  Item  {          String  name   }   ! def  o  =  new  Order(          line:  new  LineItem(                  quantity:  2,                  item:  null))   With Java, you only get an NPE. No idea where it came from! ! println  o.line.item.name @glaforge — @smaldini / #DV13-rtweb !72
  • 202. Null handling class  Order  {          LineItem  line   }   class  LineItem  {          int  quantity          Item  item   }   class  Item  {          String  name   }   ! def  o  =  new  Order(          line:  new  LineItem(                  quantity:  2,                  item:  null))   ! println  o.line.item.name @glaforge — @smaldini / #DV13-rtweb With Java, you only get an NPE. No idea where it came from! Groovy will say: Cannot get property ‘name’ on null object !72
  • 203. Null handling class  Order  {          LineItem  line   }   class  LineItem  {          int  quantity          Item  item   }   class  Item  {          String  name   }   ! def  o  =  new  Order(          line:  new  LineItem(                  quantity:  2,                  item:  null))   ! println  o.line.item.name @glaforge — @smaldini / #DV13-rtweb !72
  • 204. Null handling class  Order  {          LineItem  line   }   class  LineItem  {          int  quantity          Item  item   }   class  Item  {          String  name   }   o?.line?.item?.name ! def  o  =  new  Order(          line:  new  LineItem(                  quantity:  2,                  item:  null))   ! println  o.line.item.name @glaforge — @smaldini / #DV13-rtweb !72
  • 205. Null handling class  Order  {          LineItem  line   }   class  LineItem  {          int  quantity          Item  item   }   class  Item  {          String  name   }   o?.line?.item?.name Safe navigation: will just return null; No NPE ! def  o  =  new  Order(          line:  new  LineItem(                  quantity:  2,                  item:  null))   ! println  o.line.item.name @glaforge — @smaldini / #DV13-rtweb !72
  • 206.
  • 208. The Truth, the Groovy Truth! And what if I could customize the truth?
  • 209. The Groovy Truth assert  !(  null  )   assert  !(    ""    )   assert  !(    []    )   assert  !(      0    ) assert  new  Object()   assert  "string"   assert  [1,  2,  3]   assert  1234 @glaforge — @smaldini / #DV13-rtweb !74
  • 210. The Groovy Truth null, empty, 0-sized, zero are coerced to false assert  !(  null  )   assert  !(    ""    )   assert  !(    []    )   assert  !(      0    ) assert  new  Object()   assert  "string"   assert  [1,  2,  3]   assert  1234 @glaforge — @smaldini / #DV13-rtweb !74
  • 211. The Groovy Truth null, empty, 0-sized, zero are coerced to false assert  !(  null  )   assert  !(    ""    )   assert  !(    []    )   assert  !(      0    ) assert  new  Object()   assert  "string"   assert  [1,  2,  3]   assert  1234 @glaforge — @smaldini / #DV13-rtweb true otherwise !74
  • 212. Customizing the truth! class  Account  {          String  name          boolean  disabled  =  false   !        boolean  asBoolean()  {  !disabled  }   }   ! assert    new  Account(name:  'current')   assert  !new  Account(name:  'old',  disabled:  true) @glaforge — @smaldini / #DV13-rtweb !75
  • 213. Customizing the truth! class  Account  {          String  name          boolean  disabled  =  false   !        boolean  asBoolean()  {  !disabled  }   }   ! assert    new  Account(name:  'current')   assert  !new  Account(name:  'old',  disabled:  true) while (account), if (account), etc… @glaforge — @smaldini / #DV13-rtweb !75
  • 214. ?:
  • 216. Towards Elvis... @glaforge — @smaldini / #DV13-rtweb !77
  • 217. Towards Elvis... def  (x,  y)  =  ['MacBook  Pro',  'unknown'] @glaforge — @smaldini / #DV13-rtweb !77
  • 218. Towards Elvis... def  (x,  y)  =  ['MacBook  Pro',  'unknown'] @glaforge — @smaldini / #DV13-rtweb !77
  • 219. Towards Elvis... def  (x,  y)  =  ['MacBook  Pro',  'unknown'] if  (x  !=  null  &&  x.size()  >  0)  x  else  y @glaforge — @smaldini / #DV13-rtweb !77
  • 220. Towards Elvis... def  (x,  y)  =  ['MacBook  Pro',  'unknown'] if  (x  !=  null  &&  x.size()  >  0)  x  else  y if  (x  &&  x.size())  x  else  y @glaforge — @smaldini / #DV13-rtweb !77
  • 221. Towards Elvis... def  (x,  y)  =  ['MacBook  Pro',  'unknown'] if  (x  !=  null  &&  x.size()  >  0)  x  else  y if  (x  &&  x.size())  x  else  y if  (x)  x  else  y @glaforge — @smaldini / #DV13-rtweb !77
  • 222. Towards Elvis... def  (x,  y)  =  ['MacBook  Pro',  'unknown'] if  (x  !=  null  &&  x.size()  >  0)  x  else  y if  (x  &&  x.size())  x  else  y if  (x)  x  else  y x  ?  x  :  y @glaforge — @smaldini / #DV13-rtweb !77
  • 223. Towards Elvis... def  (x,  y)  =  ['MacBook  Pro',  'unknown'] if  (x  !=  null  &&  x.size()  >  0)  x  else  y if  (x  &&  x.size())  x  else  y if  (x)  x  else  y x  ?  x  :  y x  ?:  y @glaforge — @smaldini / #DV13-rtweb !77
  • 224. Towards Elvis... def  (x,  y)  =  ['MacBook  Pro',  'unknown'] if  (x  !=  null  &&  x.size()  >  0)  x  else  y if  (x  &&  x.size())  x  else  y if  (x)  x  else  y x  ?  x  :  y x  ?:  y Null, empty, zerosized... false, otherwise true! @glaforge — @smaldini / #DV13-rtweb !77
  • 225. Towards Elvis... def  (x,  y)  =  ['MacBook  Pro',  'unknown'] if  (x  !=  null  &&  x.size()  >  0)  x  else  y if  (x  &&  x.size())  x  else  y if  (x)  x  else  y x  ?  x  :  y x  ?:  y Good old ternary operator @glaforge — @smaldini / #DV13-rtweb Null, empty, zerosized... false, otherwise true! !77
  • 226. Towards Elvis... def  (x,  y)  =  ['MacBook  Pro',  'unknown'] if  (x  !=  null  &&  x.size()  >  0)  x  else  y if  (x  &&  x.size())  x  else  y if  (x)  x  else  y x  ?  x  :  y x  ?:  y Elvis! @glaforge — @smaldini / #DV13-rtweb Good old ternary operator Null, empty, zerosized... false, otherwise true! !77
  • 227. AST transformations • Abstract Syntax Tree – in memory representation of your program
 before being compiled into bytecode ! • AST transformation == process of transforming the AST of a program before it’s compiled ! • Macro-like compiler hook! @glaforge — @smaldini / #DV13-rtweb !78
  • 228. Lots of AST transformations... • Code generation – @ToString, @EqualsAndHashCode, @Canonical, @TupleConstructor, @InheritConstructors, @Category, @IndexedProperty, @Lazy, @Newify • Class design – @Delegate, @Immutable, @Memoized, 
 @Singleton, @Mixin • Logging – @Log, @Log4j, @Log4j2, @Slf4j @glaforge — @smaldini / #DV13-rtweb !79
  • 229. Lots of AST transformations... • Safer scripting – @ConditionalInterrupt, @ThreadInterrupt, @TimedInterupt • Compiler directives – @Field, @PackageScope, @AnnotationCollector, @DelegatesTo, @TypeChecked, @CompileStatic, @CompileDynamic • Swing patterns – @Bindable, @ListenerList, @Vetoable @glaforge — @smaldini / #DV13-rtweb !80
  • 230. Lots of AST transformations... • Dependencies handling – @Grab, @GrabConfig, @GrabExclude, @GrabResolver • Test assistance – @NotYetImplemented, @ASTTest @glaforge — @smaldini / #DV13-rtweb !81
  • 231. Immutability • Implement immutability 
 by the book ! – final class – tuple-style constructor – private final backing fields – defensive copying of collections – equals() and hashCode() methods – toString() method – ... @glaforge — @smaldini / #DV13-rtweb !82
  • 232. Immutability • Implement immutability 
 by the book ! Can be error-prone to write immutable classes oneself! – final class – tuple-style constructor – private final backing fields – defensive copying of collections – equals() and hashCode() methods – toString() method – ... @glaforge — @smaldini / #DV13-rtweb !82
  • 233. Immutability • A Person class with – a String name – an int age public final class Person {! private final String name;! private final int age;! ! ! ! ! ! ! public Person(String name, int age) {! this.name = name;! this.age = age;! }! public String getName() {! return name;! }! public int getAge() {! return age;! }! public int hashCode() {! return age + 31 * name.hashCode();! }! public boolean equals(Object other) {! if (other == null) {! return false;! }! if (this == other) {! return true;! }! if (Person.class != other.getClass()) {! return false;! }! Person otherPerson = (Person)other;! if (!name.equals(otherPerson.getName()) {! return false;! }! if (age != otherPerson.getAge()) {! return false;! }! return true;! }! public String toString() {! return "Person(" + name + ", " + age + ")";! }! }! @glaforge — @smaldini / #DV13-rtweb !83
  • 234. Immutability • A Person class with – a String name – an int age public final class Person {! private final String name;! private final int age;! ! ! ! ! ! ! public Person(String name, int age) {! this.name = name;! this.age = age;! }! Damn verbose Java! public String getName() {! return name;! }! public int getAge() {! return age;! }! public int hashCode() {! return age + 31 * name.hashCode();! }! public boolean equals(Object other) {! if (other == null) {! return false;! }! if (this == other) {! return true;! }! if (Person.class != other.getClass()) {! return false;! }! Person otherPerson = (Person)other;! if (!name.equals(otherPerson.getName()) {! return false;! }! if (age != otherPerson.getAge()) {! return false;! }! return true;! }! public String toString() {! return "Person(" + name + ", " + age + ")";! }! }! @glaforge — @smaldini / #DV13-rtweb !83
  • 235. Immutability • A Person class with – a String name – an int age public final class Person {! private final String name;! private final int age;! ! ! ! ! ! ! public Person(String name, int age) {! this.name = name;! this.age = age;! }! Damn verbose Java! public String getName() {! return name;! }! public int getAge() {! return age;! }! public int hashCode() {! return age + 31 * name.hashCode();! }! public boolean equals(Object other) {! if (other == null) {! return false;! }! if (this == other) {! return true;! }! if (Person.class != other.getClass()) {! return false;! }! Person otherPerson = (Person)other;! if (!name.equals(otherPerson.getName()) {! return false;! }! if (age != otherPerson.getAge()) {! return false;! }! return true;! }! Although it’s also a valid Groovy program! public String toString() {! return "Person(" + name + ", " + age + ")";! }! }! @glaforge — @smaldini / #DV13-rtweb !83
  • 236. @Immutable import  groovy.transform.*   ! @Immutable   class  Person  {          String  name          int  age   } @glaforge — @smaldini / #DV13-rtweb !84
  • 237. Memoization • Cache the result of previous invocations of closures or methods with the same set of argument values import  groovy.transform.*   ! @Memoized   long  fib(long  n)  {          if  (n  ==  0)  0          else  if  (n  ==  1)  1          else  fib(n  -­‐  1)  +  fib(n  -­‐  2)   }   ! println  fib(40) @glaforge — @smaldini / #DV13-rtweb !85
  • 238. Memoization • Cache the result of previous invocations of closures or methods with the same set of argument values import  groovy.transform.*   Best applied to side-effect free functions ! @Memoized   long  fib(long  n)  {          if  (n  ==  0)  0          else  if  (n  ==  1)  1          else  fib(n  -­‐  1)  +  fib(n  -­‐  2)   }   ! println  fib(40) @glaforge — @smaldini / #DV13-rtweb !85
  • 239.
  • 241. Groovy allows you to be lazy The compiler will do the job for you
  • 242. Groovy allows you to be lazy More concise, more readable code The compiler will do the job for you
  • 243. Groovy allows you to be lazy More concise, more readable code The compiler will do the job for you Less stuff to maintain and worry about
  • 244. @TypeChecked & @CompileStatic • Static type checking with @TypeChecked, throws compilation errors on... – typos in method and variable names – incompatible return types – wrong type assignments ! • Supports fine-grained type inference – « Least Upper Bound » – « Flow typing » @glaforge — @smaldini / #DV13-rtweb !87
  • 245. @TypeChecked & @CompileStatic • Static type checking with @TypeChecked, throws compilation errors on... – typos in method and variable names – incompatible return types – wrong type assignments ! You can even extend the static type checker! • Supports fine-grained type inference – « Least Upper Bound » – « Flow typing » @glaforge — @smaldini / #DV13-rtweb !87
  • 246. @TypeChecked & @CompileStatic • Static type checking with @TypeChecked, throws compilation errors on... – typos in method and variable names – incompatible return types – wrong type assignments ! You can even extend the static type checker! • Supports fine-grained type inference – « Least Upper Bound » – « Flow typing » @glaforge — @smaldini / #DV13-rtweb Type check DSLs or dynamic features! !87