Traits: a simple example 9 trait
FlyingAbility
{
String
fly()
{
"I'm
flying!"
}
}
! class
Bird
implements
FlyingAbility
{}
def
b
=
new
Bird()
! assert
b.fly()
==
"I'm
flying!" « trait », a new keyword for a new concept
Traits: a simple example 9 trait
FlyingAbility
{
String
fly()
{
"I'm
flying!"
}
}
! class
Bird
implements
FlyingAbility
{}
def
b
=
new
Bird()
! assert
b.fly()
==
"I'm
flying!" a class « implements » a trait
Traits: a simple example 9 trait
FlyingAbility
{
String
fly()
{
"I'm
flying!"
}
}
! class
Bird
implements
FlyingAbility
{}
def
b
=
new
Bird()
! assert
b.fly()
==
"I'm
flying!" the fly() method from the trait is available
Traits: stateful 10 trait
Named
{
String
name
}
! class
Bird
implements
Named
{}
def
b
=
new
Bird(name:
'Colibri')
! assert
b.name
==
'Colibri' a Groovy property
Traits: stateful 10 trait
Named
{
String
name
}
! class
Bird
implements
Named
{}
def
b
=
new
Bird(name:
'Colibri')
! assert
b.name
==
'Colibri' implement the trait
Traits: stateful 10 trait
Named
{
String
name
}
! class
Bird
implements
Named
{}
def
b
=
new
Bird(name:
'Colibri')
! assert
b.name
==
'Colibri' Groovy named argument constructor
Traits: stateful 10 trait
Named
{
String
name
}
! class
Bird
implements
Named
{}
def
b
=
new
Bird(name:
'Colibri')
! assert
b.name
==
'Colibri' access the property
Traits: what about conflicts? 12 trait
KiteSurfer
{
String
surf()
{
'kite'
}
}
! trait
WebSurfer
{
String
surf()
{
'web'
}
}
! class
Person
{
String
name
}
! class
Hipster
extends
Person
implements
KiteSurfer,
WebSurfer
{}
! def
h
=
new
Hipster()
assert
h.surf()
==
'web' extending a class and implementing the two traits
Traits: what about conflicts? 14 trait
KiteSurfer
{
String
surf()
{
'kite'
}
}
! trait
WebSurfer
{
String
surf()
{
'web'
}
}
! class
Person
{
String
name
}
! class
Hipster
extends
Person
implements
WebSurfer,
KiteSurfer
{
String
surf()
{
KiteSurfer.super.surf()
}
}
! def
h
=
new
Hipster()
assert
h.surf()
==
'kite' Your class method takes precedence over the traits
trait
Named
{
String
name
}
! class
Animal
{}
class
NamedAnimal
implements
Named
{}
! def
na
=
new
NamedAnimal(name:
'Felix')
! assert
na.name
==
'Felix' Traits: runtime implementation 15
trait
Named
{
String
name
}
! class
Animal
{}
class
NamedAnimal
implements
Named
{}
! def
na
=
new
NamedAnimal(name:
'Felix')
! assert
na.name
==
'Felix' Traits: runtime implementation 15 Somewhat artificial to have to create an intermediary class to get named animals
trait
Named
{
String
name
}
! class
Animal
{}
class
NamedAnimal
implements
Named
{}
! def
na
=
new
NamedAnimal(name:
'Felix')
! assert
na.name
==
'Felix' Traits: runtime implementation 15
trait
Named
{
String
name
}
! class
Animal
{}
! ! def
na
=
new
Animal()
as
Named
na.name
=
'Felix'
assert
na.name
==
'Felix' Traits: runtime implementation 16
trait
Named
{
String
name
}
! class
Animal
{}
! ! def
na
=
new
Animal()
as
Named
na.name
=
'Felix'
assert
na.name
==
'Felix' Traits: runtime implementation 16 Runtime trait, with Groovy’s usual coercion mechanism
trait
Named
{
String
name
}
! class
Animal
{}
! ! def
na
=
new
Animal()
as
Named
na.name
=
'Felix'
assert
na.name
==
'Felix' Traits: runtime implementation 16
New: @TailRecursive 19 import
groovy.transform.TailRecursive
! @TailRecursive
def
fact(BigInteger
n,
accu
=
1G)
{
if
(n
<
2)
accu
else
fact(n
-‐
1,
n
*
accu)
}
! assert
fact(1000)
>
10e2566 Downside of tail recursion is you might have to rewrite your algo to be tailrec friendly
New: @Sortable 20 import
groovy.transform.*
! @Sortable
class
Person
{
String
lastName
String
firstName
int
age
} Makes the class Comparable by multiple Comparators
New: @Sortable 20 import
groovy.transform.*
! @Sortable
class
Person
{
String
lastName
String
firstName
int
age
} First compare by lastName, then by firstName, etc.
New: @Sortable 20 import
groovy.transform.*
! @Sortable
class
Person
{
String
lastName
String
firstName
int
age
} You can also specify ‘includes’ / ‘excludes’ properties
@BaseScript improvements 21 abstract
class
CustomBase
extends
Script
{
int
meaningOfLife
=
42
} @BaseScript(CustomBase)
import
groovy.transform.BaseScript
! assert
meaningOfLife
==
42 You can add your own base methods and properties to all compiled scripts
@BaseScript improvements 21 abstract
class
CustomBase
extends
Script
{
int
meaningOfLife
=
42
} @BaseScript(CustomBase)
import
groovy.transform.BaseScript
! assert
meaningOfLife
==
42 Define the base script class for this script
JDK 7+ NIO2 module • All the familiar methods on File retrofitted on Path as well 24 path.withReader
{
Reader
r
-‐>
...
}
path.eachLine
{
String
line
-‐>
...
}
path.eachFileRecurse
{
Path
p
-‐>
...
}
path
<<
'some
content'
path
<<
bytes
path.readLines()
… Feature request to add all the java.nio.file.Files static utility methods as GDK
JSON parser / builder perf. increase • Re-implementation of JSON support for speed & efficiency
• parser forked off the Boon JSON project
• serializer carefully fine-tuned
! • Article on the parsing speed improvements
• http://rick-hightower.blogspot.fr/2014/04/groovy-and-boon-provide-fastest-json.html 26 Benchmark gives 3x to 4x performance factor over Jackson and GSON
Markup template engine — the idea 31 cars
{
cars.each
{
car(make:
it.make,
name:
it.name)
}
} model = [cars: [! new Car(make: 'Peugeot', name: '508'), ! new Car(make: 'Toyota', name: 'Prius’)! ]] Feed a model into your template
Groovy Macros ! • Authoring AST transformations can be verbose: 46 def
someVariable
=
new
ConstantExpression("xyz")
def
returnStatement
=
new
ReturnStatement(
new
ConstructorCallExpression(
ClassHelper.make(SomeCoolClass),
new
ArgumentListExpression(someVariable)
)
)