• similar to Java 8 interface default methods • Elegant way to compose behavior • multiple inheritance, without the « diamond problem » • Traits can also be stateful • traits can have properties like normal classes • Compatible with static typing & compilation • class methods coming from traits are also visible from Java • Also possible to implement traits at runtime
fly() { "I'm flying!" } } ! class Bird implements FlyingAbility {} def b = new Bird() ! assert b.fly() == "I'm flying!" Traits: a simple example « trait », a new keyword for a new concept
fly() { "I'm flying!" } } ! class Bird implements FlyingAbility {} def b = new Bird() ! assert b.fly() == "I'm flying!" Traits: a simple example a class « implements » a trait
fly() { "I'm flying!" } } ! class Bird implements FlyingAbility {} def b = new Bird() ! assert b.fly() == "I'm flying!" Traits: a simple example the fly() method from the trait is available
name } ! class Bird implements Named {} def b = new Bird(name: 'Colibri') ! assert b.name == 'Colibri' Traits: stateful Groovy named argument constructor
} ! trait WebSurfer { String surf() { 'web' } } ! class Person { String name } ! class Hipster extends Person implements KiteSurfer, WebSurfer {} ! def h = new Hipster() assert h.surf() == 'web' Traits: what about conflicts?
} ! trait WebSurfer { String surf() { 'web' } } ! class Person { String name } ! class Hipster extends Person implements KiteSurfer, WebSurfer {} ! def h = new Hipster() assert h.surf() == 'web' Traits: what about conflicts? two surf() methods
} ! trait WebSurfer { String surf() { 'web' } } ! class Person { String name } ! class Hipster extends Person implements KiteSurfer, WebSurfer {} ! def h = new Hipster() assert h.surf() == 'web' Traits: what about conflicts?
} ! trait WebSurfer { String surf() { 'web' } } ! class Person { String name } ! class Hipster extends Person implements KiteSurfer, WebSurfer {} ! def h = new Hipster() assert h.surf() == 'web' Traits: what about conflicts? extending a class and implementing the two traits
} ! trait WebSurfer { String surf() { 'web' } } ! class Person { String name } ! class Hipster extends Person implements KiteSurfer, WebSurfer {} ! def h = new Hipster() assert h.surf() == 'web' Traits: what about conflicts?
} ! trait WebSurfer { String surf() { 'web' } } ! class Person { String name } ! class Hipster extends Person implements KiteSurfer, WebSurfer {} ! def h = new Hipster() assert h.surf() == 'web' Traits: what about conflicts? last declared trait wins!
} ! trait WebSurfer { String surf() { 'web' } } ! class Person { String name } ! class Hipster extends Person implements KiteSurfer, WebSurfer {} ! def h = new Hipster() assert h.surf() == 'web' Traits: what about conflicts?
} ! trait WebSurfer { String surf() { 'web' } } ! class Person { String name } ! class Hipster extends Person implements WebSurfer, KiteSurfer {} ! def h = new Hipster() assert h.surf() == 'kite' Traits: what about conflicts?
} ! trait WebSurfer { String surf() { 'web' } } ! class Person { String name } ! class Hipster extends Person implements WebSurfer, KiteSurfer {} ! def h = new Hipster() assert h.surf() == 'kite' Traits: what about conflicts? reverse the order!
} ! trait WebSurfer { String surf() { 'web' } } ! class Person { String name } ! class Hipster extends Person implements WebSurfer, KiteSurfer {} ! def h = new Hipster() assert h.surf() == 'kite' Traits: what about conflicts?
} ! 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' Traits: what about conflicts? Be explicit! Override surf() & use ‘super’
} ! 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' Traits: what about conflicts? Your class method takes precedence over the traits
String toString() { "a ${this.class.name} instance" } } ! class Foo implements CustomToString {} ! assert new Foo().toString() != 'a Foo instance' Traits: forcing method override ‘this’ is the ‘this’ of the class implementing the trait
String toString() { "a ${this.class.name} instance" } } ! class Foo implements CustomToString {} ! assert new Foo().toString() != 'a Foo instance' Traits: forcing method override The default Object#toString() method always prevails, in spite of the trait’s toString()
@ForceOverride String toString() { "a ${this.class.name} instance" } } ! class Foo implements CustomToString {} ! assert new Foo().toString() == 'a Foo instance' Traits: forcing method override Use @ForceOverride to force the compiler to use the trait’s method
name } ! class Animal {} class NamedAnimal implements Named {} ! def na = new NamedAnimal(name: 'Felix') ! assert na.name == 'Felix' Traits: runtime implementation
name } ! class Animal {} class NamedAnimal implements Named {} ! def na = new NamedAnimal(name: 'Felix') ! assert na.name == 'Felix' Traits: runtime implementation Somewhat artificial to have to create an intermediary class to get named animals
name } ! class Animal {} class NamedAnimal implements Named {} ! def na = new NamedAnimal(name: 'Felix') ! assert na.name == 'Felix' Traits: runtime implementation
name } ! class Animal {} ! ! def na = new Animal() as Named na.name = 'Felix' assert na.name == 'Felix' Traits: runtime implementation Runtime trait, with Groovy’s usual coercion mechanism
private fields and methods • have abstract methods • implement interfaces • extend other traits or implement several traits • be statically type checked and compiled
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
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
int meaningOfLife = 42 } @BaseScript(CustomBase) import groovy.transform.BaseScript ! assert meaningOfLife == 42 Define the base script class for this script
int meaningOfLife = 42 } @BaseScript(CustomBase) import groovy.transform.BaseScript ! assert meaningOfLife == 42 In 2.3, ability to put the annotation on imports & package
methods on File retrofitted on Path as well 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 methods
of JSON support for speed & efficiency • parser forked of 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
of JSON support for speed & efficiency • parser forked of 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
of JSON support for speed & efficiency • parser forked of 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 Benchmark gives 3x to 4x performance factor over Jackson and GSON
of JSON support for speed & efficiency • parser forked of 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
to JsonSlurperClassic • Additional parsing modes: • INDEX_OVERLAY: super fast for <2MB payloads • using a « parsing overlay » technique • CHARACTER_SOURCE: for >2MB payloads • implemented with sliding windows over readers • LAX: beyond the JSON spec, nice for configuration files • support single quotes, / and # comments • CHAR_BUFFER: general purpose
of Groovy’s « builders » • and particularly the MarkupBuilder class for generating arbitrary XML / HTML payloads • Compiled statically for fast template rendering • Internationalization aware • provide the desired Locale in the configuration object • usual suffix notation template_fr_FR.tpl • Custom base template class • ability to provide reusable methods across your templates
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
available • use createTypeCheckedModelTemplate() instead of createTemplate() • Advantages • get compilation errors • if a variable is not available • if you make mistakes in the code snippets • even faster templates
leverage and build upon JDK 7+ invoke dynamic • get Java-like performance even for dynamic code • Rationalize the sedimentation of meta-programming • more coherence, less corner cases & inconsistencies • Provide a notion of « realm » • shield users of « monkey patching » • finer-grained control of meta-programming reach • Private visibility anyone?
uses Antlr v2! • but version 3 and 4 are out • Groovy’s grammar evolved from a Java grammar • harder to fix and evolve, especially with Antlr v2 ! • Advantages • Start from a clean slate • Antlr 4 more tolerant and powerful regarding ambiguities • Time to clean some grammar & syntax warts! • Need to implement the Java 8 constructs!
uses Antlr v2! • but version 3 and 4 are out • Groovy’s grammar evolved from a Java grammar • harder to fix and evolve, especially with Antlr v2 ! • Advantages • Start from a clean slate • Antlr 4 more tolerant and powerful regarding ambiguities • Time to clean some grammar & syntax warts! • Need to implement the Java 8 constructs! A « Groovy Summer of Code » student to help
features to support • to keep saying Groovy / Java interoperability is awesome! • New in Java 8 • lambdas • method references • default methods in interfaces • stream API, date / time API • annotations on types & repeated annotations
features to support • to keep saying Groovy / Java interoperability is awesome! • New in Java 8 • lambdas • method references • default methods in interfaces • stream API, date / time API • annotations on types & repeated annotations Groovy had already: closures, method pointers, mixins, enriched collection & time APIs
— By-Nc-Sa • http://www.flickr.com/photos/22914687@N05/4957591422/sizes/l/ • Sous la Tour Eiffel — By-Nc-Sa • http://www.flickr.com/photos/stewiedewie/244850735/sizes/l/in/photostream/ • Sous le pont — By-Nc-Nd • http://www.landscape-photo.net/displayimage.php?pid=5194 • Paris Metro - By-Nc-Sa • http://www.flickr.com/photos/22914687@N05/6317047263/sizes/l/ ! • Slide template created by @glaforge, completed by @nmartignole for Devoxx FR2014