<<

groovy - groovy - /awesome asert/awesome - paulk_asert paulk_asert @ Dr Paul King Dr Paul Apache : The Awesome Parts Awesome The Groovy Lead for Object Computing Inc. Computing Object Groovy for Lead https://github.com/paulk http:/slideshare.net/

© ASERT 2006-2016 © ASERT 2006-2016 time - class class FP) st

, macros metaprogramming, boiler plate code boiler plate + runtime & compile & + runtime (DSLs) grammar + flexible & GDK + scripting – (1 + closures system type + extensible What is Groovy? is What

Groovy = = Java Groovy

extensibility.” provides provides great flexibility and adds adds productivity features and It leverages It leverages features Java but “Groovy “Groovy super a is like version of Java.

© ASERT 2006-2016 © ASERT 2006-2016 Java Why Groovy? Why

© ASERT 2006-2016 XXX I need feature Evolves too slowly Support More flexibility Java Why Groovy? Why Too verbose Too

Better

forsome concurrency situations Too complex Too

© ASERT 2006-2016 simple Support scripting Make it Make simpler Why Groovy? Why Groovy Make it Make dynamic

© ASERT 2006-2016 simple Support scripting Make it Make simpler Java integration Why Groovy? Why Groovy Make it Make dynamic

© ASERT 2006-2016 support Good IDE Good simple Support scripting Make it Make simpler Java integration Why Groovy? Why Groovy Make it Make dynamic

© ASERT 2006-2016 support Good IDE Good simple Support scripting Make it Make simpler Java integration Why Groovy? Why Groovy Make it Make dynamic Custom features

© ASERT 2006-2016 support Good IDE Good simple Support scripting Support concurrency Make it Make simpler Java integration Why Groovy? Why Groovy Make it Make dynamic Custom features

© ASERT 2006-2016 support Good IDE Good simple Support scripting Support concurrency Make it Make simpler Java integration Why Groovy? Why Groovy

Make it Make dynamic Custom features

style Support functional

© ASERT 2006-2016 © ASERT 2006-2016 Java code for list manipulation

import java.util.List; import java.util.ArrayList;

class Main { private List keepShorterThan(List strings, int length) { List result = new ArrayList(); for (int i = 0; i < strings.size(); i++) { String s = (String) strings.get(i); if (s.length() < length) { result.add(s); } © ASERT 2006 ASERT © } return result; }

public static void main(String[] args) { - 2016 List names = new ArrayList(); names.add("Ted"); names.add("Fred"); names.add("Jed"); names.add("Ned"); System.out.println(names); Main m = new Main(); List shortNames = m.keepShorterThan(names, 4); System.out.println(shortNames.size()); for (int i = 0; i < shortNames.size(); i++) { String s = (String) shortNames.get(i); System.out.println(s); } } } Groovy code for list manipulation

import java.util.List; import java.util.ArrayList;

class Main { private List keepShorterThan(List strings, int length) { List result = new ArrayList(); for (int i = 0; i < strings.size(); i++) { String s = (String) strings.get(i); Rename if (s.length() < length) { Main.java result.add(s); to } © ASERT 2006 ASERT © Main.groovy } return result; }

public static void main(String[] args) { - 2016 List names = new ArrayList(); names.add("Ted"); names.add("Fred"); names.add("Jed"); names.add("Ned"); System.out.println(names); Main m = new Main(); List shortNames = m.keepShorterThan(names, 4); System.out.println(shortNames.size()); for (int i = 0; i < shortNames.size(); i++) { String s = (String) shortNames.get(i); System.out.println(s); } } } Some Java Boilerplate identified import java.util.List; Are the semicolons import java.util.ArrayList; needed? class Main { And shouldn’t private List keepShorterThan(List strings, int length) { List result = new ArrayList(); we us more for (int i = 0; i < strings.size(); i++) { modern list String s = (String) strings.get(i); notation? if (s.length() < length) { result.add(s); Why not }

© ASERT 2006 ASERT © import common } return result; libraries? } Do we need

public static void main(String[] args) { - 2016 List names = new ArrayList(); the static types? names.add("Ted"); names.add("Fred"); Must we always names.add("Jed"); names.add("Ned"); have a main System.out.println(names); Main m = new Main(); method and List shortNames = m.keepShorterThan(names, 4); class definition? System.out.println(shortNames.size()); for (int i = 0; i < shortNames.size(); i++) { How about String s = (String) shortNames.get(i); improved System.out.println(s); } consistency? } } Java Boilerplate removed

def keepShorterThan(strings, length) { def result = new ArrayList() for (s in strings) { if (s.size() < length) { result.add(s) } } return result © ASERT 2006 ASERT © }

names = new ArrayList() - 2016 names.add("Ted"); names.add("Fred") names.add("Jed"); names.add("Ned") System.out.println(names) shortNames = keepShorterThan(names, 4) System.out.println(shortNames.size()) for (s in shortNames) { System.out.println(s) } More Java Boilerplate identified

def keepShorterThan(strings, length) { Shouldn’t we def result = new ArrayList() have special for (s in strings) { if (s.size() < length) { notation for lists? result.add(s) And special } facilities for } return result list processing? © ASERT 2006 ASERT © } Is ‘return’ needed at end?

names = new ArrayList() - 2016 names.add("Ted"); names.add("Fred") Is the method names.add("Jed"); names.add("Ned") now needed? System.out.println(names) Simplify common shortNames = keepShorterThan(names, 4) System.out.println(shortNames.size()) methods? for (s in shortNames) { Remove unambiguous System.out.println(s) brackets? } Boilerplate removed = nicer Groovy version names = ["Ted", "Fred", "Jed", "Ned"] println names shortNames = names.findAll{ it.size() < 4 } println shortNames.size()

shortNames.each{ println it } © ASERT 2006 ASERT ©

Output: - 2016 ["Ted", "Fred", "Jed", "Ned"] 3 Ted Jed Ned Or Groovy DSL version if required

given the names "Ted", "Fred", "Jed" and "Ned" display all the names display the number of names having size less than 4

display the names having size less than 4 © ASERT 2006 ASERT ©

// plus a DSL implementation

- 2016 Or Groovy DSL version if required

given the names "Ted", "Fred", "Jed" and "Ned" display all the names display the number of names having size less than 4

display the names having size less than 4 © ASERT 2006 ASERT ©

names = [] def of, having, less

def given(_the) { [names:{ Object[] ns -> names.addAll(ns) - 2016 [and: { n -> names += n }] }] } def the = [ number: { _of -> [names: { _having -> [size: { _less -> [than: { size -> println names.findAll{ it.size() < size }.size() }]}] }] }, names: { _having -> [size: { _less -> [than: { size -> names.findAll{ it.size() < size }.each{ println it } }]}] } ] def all = [the: { println it }] def display(arg) { arg } Or Groovy DSL version if required

given the names "Ted", "Fred", "Jed" and "Ned" display all the names display the number of names having size less than 4

display the names having size less than 4

© ASERT 2006 ASERT ©

- 2016

• Or use GDSL (IntelliJ IDEA) or DSLD () Or typed Groovy DSL version if required

given the names "Ted", "Fred", "Jed" and "Ned" display all the names display the number of names having size less than 4 display the names having size less than 4

© ASERT 2006 ASERT © … enum The { the } enum Having { having }

enum Of { of } - 2016 … class DisplayThe { DisplayTheNamesHaving names(Having having) { new DisplayTheNamesHaving() } DisplayTheNumberOf number(Of of) { new DisplayTheNumberOf() } } … // plus 50 lines

Or typed Groovy DSL version if required

© ASERT 2006 ASERT ©

- 2016

Groovy DSL being debugged

© ASERT 2006 ASERT ©

- 2016 Or typed Groovy DSL version if required

@TypeChecked(extensions='EdChecker.groovy') def method() { given the names "Ted", "Fred", "Jed" and "Ned" display all the names display the number of names having size less than 4 display the names having size less than 4 }

© ASERT 2006 ASERT © afterMethodCall { mc -> mc.arguments.each {

if (isConstantExpression(it)) { -

2016 if (it.value instanceof String && !it.value.endsWith('ed')) { addStaticTypeError("I don't like the name '${it.value}'", mc) } } } } Or typed Groovy DSL version if required

@TypeChecked(extensions='EdChecker.groovy') def method() { given the names "Ted", "Fred", "Jed" and "Ned" display all the names display the number of names having size less than 4 display the names having size less than 4 }

© ASERT 2006 ASERT © afterMethodCall { mc -> mc.arguments.each {

if (isConstantExpression(it)) { -

2016 if (it.value instanceof String && !it.value.endsWith('ed')) { addStaticTypeError("I don't like the name '${it.value}'", mc) } } } } Or typed Groovy DSL version if required

@TypeChecked(extensions='EdChecker.groovy') def method() { given the names "Ted", "Mary", "Jed" and "Pete" display all the names display the number of names having size less than 4 display the names having size less than 4 }

© ASERT 2006 ASERT © afterMethodCall { mc -> mc.arguments.each {

if (isConstantExpression(it)) { -

2016 if (it.value instanceof String && !it.value.endsWith('ed')) { addStaticTypeError("I don't like the name '${it.value}'", mc) } } } } What style of language is Groovy? Groovy Style

• Imperative/OO but somewhat paradigm agnostic • Dynamic, optionally static (gradual extensible typing) • Extensible language features through metaprogramming What makes Groovy Awesome? • Java integration • Scripting support • Multiparadigm • Gradual typing Awesome • Metaprogramming • Domain specific language (DSL) support • Ecosystem • Community/Team What makes Groovy Awesome? • Java integration – Builds up on Java – Tight integration – Polyglot friendly • Scripting support • Multiparadigm • Gradual typing • Metaprogramming • Domain Specific Language support • Ecosystem • Community/Team Java Integration • Groovy is Java’s friend

Awesome

Groovy

Java Java Integration • Standing on the shoulders of Giants Groovy – Some limitations inherited but much Java gained through new releases of Java – Rock solid foundation – Can ease migration to new versions of Java Java Integration • Seamless integration – IDEs provide cross- Groovy language compile, navigation, and refactoring Java – Arbitrarily mix source language – Drop-in replace any class – Overloaded methods – Syntax alignment – Shared data types Java Integration • Seamless integration – IDEs provide cross- Groovy language compile, navigation, and refactoring Java – Arbitrarily mix source language – Drop-in replace any class – Overloaded methods – Syntax alignment – Shared data types Java Integration • Polyglot friendly – Typically integrates well with other languages which integrate with Java – JRuby – – Scala – Frege – through Renjin – JavaScript (Rhino/Nashorn) Java Integration • Polyglot friendly JavaScript Groovy – JSR-223 scripting to talk to JavaScript Java import javax.script.ScriptEngineManager def mgr = new ScriptEngineManager() def engine = mgr.getEngineByName('nashorn') assert engine.eval(''' function factorial(n) { if (n == 0) { return 1; } return n * factorial(n - 1); } factorial(4) ''') == 24.0 Java Integration • Polyglot friendly: R integration

@GrabResolver('https://nexus.bedatadriven.com/content/groups/public') @Grab('org.renjin:renjin-script-engine:0.7.0-RC7') import javax.script.ScriptEngineManager def mgr = new ScriptEngineManager() def engine = mgr.getEngineByName('Renjin') engine.with { eval ''' factorial <- function(x) { R Groovy y <- 1 for (i in 1:x) { y <- y * i } Java return(y) } ''' assert eval('factorial(4)')[0] == 24 } Grooscript

Jorge Franco, grooscript.org Convert Groovy subset to JavaScript Support: , , NPM Demos: react.js, node.js, Pollock Converts: Classes, closures, Date primitives, ranges, String/GString Special: builder, templates, gQuery

@Grab('org.grooscript:grooscript:1.2.0') import org.grooscript.GrooScript import javax.script.ScriptEngineManager Hello Groovy! Hello JavaScript! def groojs = GrooScript.convert ''' Hello GrooScript! def sayHello = { println "Hello ${it}!" } ['Groovy','JavaScript','GrooScript'].each sayHello''', [initialText: 'var console = { log: print }', addGsLib: 'grooscript.min'] new ScriptEngineManager().getEngineByName("nashorn").eval(groojs) What makes Groovy Awesome? • Java integration • Scripting support – Simplified scripting – Separation of concerns – Security sandbox • Multiparadigm • Gradual typing • Metaprogramming • Domain Specific Language support • Ecosystem • Community/Team Scripting • Terse format • Isolation • Domain-Specific Languages (DSLs) • Security • Flexibility Awesome Scripting • Leave out surrounding class

public class Script { public static void main(String[] args) { System.out.println("Hello world"); } }

• Entire source file:

println "Hello world" Scripting • Various approaches supported – GroovyShell – GroovyScriptEngine – GroovyClassLoader – Spring – JSR-223 • Base scripts – allows predefined methods • Binding – allows predefined variables • Customizers – add imports, static imports – lock down AST to a subset – apply any AST transform transparently Scripting Scripting Scripting Scripting

class Robot { void move(dir) { println "robot moved $dir" } }

def robot = new Robot() Scripting

import static Direction.*

enum Direction { left, right, forward, backward }

class Robot { void move(Direction dir) { println "robot moved $dir" } }

def robot = new Robot()

robot.move left Scripting def robot = new Robot() def binding = new Binding( robot: robot, move: robot.&move, *: Direction.values().collectEntries { [(it.name()): it] } ) def shell = new GroovyShell(binding) shell.evaluate new File(args[0]).text

move left What makes Groovy Awesome? • Java integration • Scripting support • Multiparadigm – Object-oriented – Functional, Closures – Logic programming – Advanced OO – Advanced functional • Gradual typing • Metaprogramming • Domain Specific Language support • Ecosystem • Community/Team Multiparadigm • Imperative roots from Java – OO abstractions: classes, interfaces, inheritance – Properties Awesome – Traits • First class functional support via closures – External libraries for advanced features • Other paradigms via libraries – Logic, dataflow, reactive Multiparadigm

Imperative/OO

Functional

Logic programming Programming paradigms

http://www.info.ucl.ac.be/~pvr/paradigmsDIAGRAMeng101.pdf Multiparadigm OO features • Classes (and scripts, GroovyBeans) • Fields (and properties) • Methods, constructors, multi-methods, named and default parameters • Inheritance (behavior and implementation), interfaces, traits • Type aliases • Packages • Special accessor notation, spread operators, GPath, safe navigation OO value add: traits

/** * Things that hop * @author Grace */ trait Hopper { String jump() { "I'm jumping!" } } class Kangaroo implements Hopper {} def skip = new Kangaroo() assert skip.jump() == "I'm jumping!" Functional features • Closures – First-class functions • Higher-order functions • Map, reduce, filter • Mutable & immutable data • Recursion • Lazy & eager evaluation • Advanced FP techniques – , Trampolines, Composition, Curry • Concurrency Closures

def twice = { int num -> num + num } assert twice(5) == 10

Awesome Closures def twice = { int num -> num + num } assert twice(5) == 10 def twice10 = { -> 2 * 10 } assert 20 == twice10() def triple = { arg -> arg * 3 } assert triple(5) == 15 def alsoTriple = { it * 3 } assert alsoTriple(6) == 18 def quadruple = twice >> twice assert quadruple(5) == 20 def forty = quadruple.curry(10) assert forty() == 40 assert [10, 15, 20] == [twice, triple, quadruple].collect{ it(5) } Closures • Used for many things in Groovy: – Iterators – Callbacks – Higher-order functions – Specialized control structures – Builders – Dynamic method definition – Resource allocation – Threads – Replace design patterns More functional style examples def fact(n) { @TailRecursive n < 2 ? 1 : n * fact(n - 1) def fact(n, accu=1G) { } if (n < 2) accu else fact(n - 1, n * accu) def fib = { long n -> } n < 2 ? 1 : call(n - 1) + call(n - 2) } def fib fib = { long n -> def sort(list) { if (n < 2) 1 if (list.size() < 2) return list else fib(n - 1) + fib(n - 2) def pivot = list[0] }.memoize() def less = list.findAll{it < pivot} def equal = list.findAll{it == pivot} def more = list.findAll{it > pivot} sort(less) + equal + sort(more) } map/filter/reduce

@Canonical class Person { String name int age } def people = [ new Person('Peter', 45), new Person('Paul', 35), new Person('Mary', 25) ] assert people .findAll{ it.age < 40 } .collect{ it.name.toUpperCase() } .sort() .join(', ') == 'MARY, PAUL' map/filter/reduce (and again with streams)

@Canonical class Person { // requires JRE 8 String name def commaSep = Collectors.joining(", ") int age assert people.stream() } .filter{ it.age < 40 } .map{ it.name.toUpperCase() } def people = [ .sorted() new Person('Peter', 45), .collect(commaSep) == 'MARY, PAUL' new Person('Paul', 35), new Person('Mary', 25) ] assert people .findAll{ it.age < 40 } .collect{ it.name.toUpperCase() } .sort() .join(', ') == 'MARY, PAUL' Advanced functional support • Java/Groovy libraries – Streams, comprehensions, persistent data structures • Functional Groovy – Functional-Java based Groovy extension module – QuickCheck style -based testing – Monad library using a minimal monad implementation – Monadic functions added to the standard Java List – Monad comprehensions – Lenses – Reader, Writer and State monads – Simple IO type – Y Combinator Logic/Constraint programming • Logic programming – Declarative style – Logic clauses for example • Constraint programming – Declarative style similar to logic programming but contain constraints which must be satisfied – Relations between variables are stated as constraints – Not a step or sequence of steps to execute, but rather the properties of a solution to be found Logic programming example

cranes have 2 legs tortoises have 4 legs there are 7 animals there are 20 legs

How many of each animal? Constraint programming example

ChocoCraneTortoise.groovy @Grab('org.choco-solver:choco-solver:4.0.0') import org.chocosolver.solver.Model def m = new Model() def totalAnimals = 7 def totalLegs = 20 def numCranes = m.intVar('Cranes', 0, totalAnimals, true) def numTortoises = m.intVar('Tortoises', 0, totalAnimals, true) def numCraneLegs = m.intScaleView(numCranes, 2) def numTortoiseLegs = m.intScaleView(numTortoises, 4) m.arithm(numCranes, '+', numTortoises, '=', totalAnimals).post() m.arithm(numCraneLegs, '+', numTortoiseLegs, '=', totalLegs).post() if (m.solver.solve()) println "$numCranes\n$numTortoises" else println "No Solutions" Cranes = 4 Tortoises = 3 See also: JSR-331 Constraint Programming API • Declarative style • Emphasizes the movement of data – models programs as a series of connected tasks • A task has explicitly defined inputs and outputs – runs as soon as all of its inputs become available • Inherently parallel 70 GPars • Library classes and DSL allowing you to handle tasks concurrently: – Data Parallelism map, filter, reduce functionality in parallel with parallel array support – Asynchronous functions extend the Java Awesome executor services to enable multi-threaded closure processing – Dataflow Concurrency supports natural shared-memory concurrency model, using single-assignment variables – Actors provide Erlang/Scala-like actors including "remote" actors on other machines – Safe Agents provide a non-blocking mt-safe reference to mutable state; like "agents" in Clojure Concurrency challenge… • Suppose we have the following calculation involving several functions:

// example adapted from Parallel Programming with .Net def (f1, f2, f3, f4) = [{ sleep 1000; it }] * 3 +

[{ x, y -> x + y }] © ASERT 2006 ASERT © def a = 5

- def b = f1(a) 2016 def = f2(a) def = f3(c) def f = f4(b, d)

assert f == 10 • And we want to use our available cores … …Concurrency challenge… • We can analyse the example’s task graph:

// example adapted from Parallel Programming with .Net def (f1, f2, f3, f4) = [{ sleep 1000; it }] * 3 +

[{ x, y -> x + y }] © ASERT 2006 ASERT © def a = 5

a a

- def b = f1(a) 2016 def c = f2(a) def d = f3(c) f1 f2 def f = f4(b, d) c b f3 assert f == 10 d f4

f …Concurrency challenge… • Manually using asynchronous functions:

// example adapted from Parallel Programming with .Net def (f1, f2, f3, f4) = [{ sleep 1000; it }] * 3 + [{ x, y -> x + y }]

import static groovyx.gpars.GParsPool.withPool © ASERT 2006 ASERT © withPool(2) {

def a = 5 a a

- 2016

def futureB = f1.callAsync(a) f1 f2 def c = f2(a) c def d = f3(c) b f3 def f = f4(futureB.get(), d) d f4 assert f == 10 } f …Concurrency challenge • And with GPars Dataflows:

def (f1, f2, f3, f4) = [{ sleep 1000; it }] * 3 + [{ x, y -> x + y }]

import groovyx.gpars.dataflow.Dataflows

import static groovyx.gpars.dataflow.Dataflow.task © ASERT 2006 ASERT © new Dataflows().with {

task { a = 5 } a a - 2016 task { b = f1(a) } task { c = f2(a) } f1 f2 task { d = f3(c) } c task { f = f4(b, d) } b f3 assert f == 10 } d f4

f …Concurrency challenge • And with GPars Dataflows:

def (f1, f2, f3, f4) = [{ sleep 1000; it }] * 3 + [{ x, y -> x + y }]

import groovyx.gpars.dataflow.Dataflows

import static groovyx.gpars.dataflow.Dataflow.task © ASERT 2006 ASERT © new Dataflows().with {

task { f = f4(b, d) } a a - 2016 task { d = f3(c) } task { c = f2(a) } f1 f2 task { b = f1(a) } c task { a = 5 } b f3 assert f == 10 } d f4

f What makes Groovy Awesome? • Java integration • Scripting support • Multiparadigm • Gradual typing – Dynamic strong typing – Static type checking – Extensible – • Metaprogramming • Domain Specific Language support • Ecosystem • Community/Team Gradual typing • Dynamic by default • Gradual typing • Static type checking • Extensible

Awesome Dynamic vs static

def myPets = ['Lassie', 'Skip']

List yourPets = ['Lassie', 'Skip']

shouldFail(ClassCastException) { 79 List ourPets = new Date() } Dynamic vs static

Gradual

def myPets = ['Lassie', 'Skip']

List yourPets = ['Lassie', 'Skip']

shouldFail(ClassCastException) { 80 List ourPets = new Date() } Type-time? Dynamic vs static

def myPets = ['Lassie', 'Skip']

List yourPets = ['Lassie', 'Skip']

shouldFail(ClassCastException) { 81 List ourPets = new Date() }

def adder = { a, b -> a + b }

assert adder(100, 200) == 300 assert adder('X', 'Y') == 'XY' Dynamic vs static

def myPets = ['Lassie', 'Skip']

List yourPets = ['Lassie', 'Skip']

shouldFail(ClassCastException) { 82 List ourPets = new Date() } Duck-typing

def adder = { a, b -> a + b }

assert adder(100, 200) == 300 assert adder('X', 'Y') == 'XY' Dynamic vs static

@TypeChecked def myMethod() { def myPets = ['Lassie', 'Skip'] def myPets = ['Lassie', 'Skip'] List yourPets = ['Lassie', 'Skip'] List yourPets = } ['Lassie', 'Skip']

shouldFail(ClassCastException) { shouldFail(CompilationFailedException) { 83 List ourPets = new Date() assertScript ''' } @groovy.transform.TypeChecked def yourMethod() { List ourPets = new Date() def adder = { a, b -> a + b } } ''' assert adder(100, 200) == 300 } assert adder('X', 'Y') == 'XY' Dynamic vs static

Extensible

@TypeChecked Inference def myMethod() { def myPets = ['Lassie', 'Skip'] def myPets = ['Lassie', 'Skip'] List yourPets = ['Lassie', 'Skip'] List yourPets = } ['Lassie', 'Skip']

shouldFail(ClassCastException) { shouldFail(CompilationFailedException) { 84 List ourPets = new Date() assertScript ''' } @groovy.transform.TypeChecked def yourMethod() { List ourPets = new Date() def adder = { a, b -> a + b } } ''' assert adder(100, 200) == 300 } assert adder('X', 'Y') == 'XY' Dynamic vs static objects

class Person { String firstName String lastName String fullName() { "$firstName $lastName" } }

def p1 = new Person(firstName: 'John', lastName: 'Wayne') assert p1.firstName == 'John' && p1.fullName() == 'John Wayne'

interface PersonI { def p2 String getFirstName() 85 p2 = [firstName: 'John', String getLastName() lastName: 'Wayne', String fullName() fullName: { } "$p2.firstName $p2.lastName" def map }] map = [getFirstName: { 'John' }, assert p2.firstName == 'John' && getLastName: {'Wayne'}, p2.fullName() == 'John Wayne' fullName: { map.getFirstName() + " ${map.getLastName()}" }]

def p3 = map as PersonI assert p3.firstName == 'John' && p3.fullName() == 'John Wayne' && p3 instanceof PersonI Extensible type checking sprintf has an Object varargs parameter, hence not normally amenable to further static checking but for constant Strings we can do better using a custom type checking plugin. import groovy.transform.TypeChecked import experimental.SprintfTypeChecker

@TypeChecked(extensions=SprintfTypeChecker) void main() { sprintf('%s will turn %d on %tF', 'John', new Date(), 21) }

[Static type checking] - Parameter types didn't match types expected from the format String: For placeholder 2 [%d] expected 'int' but was 'java.util.Date' For placeholder 3 [%tF] expected 'java.util.Date' but was 'int' Extensible type checking

import groovy..Sql import groovy.transform.TypeChecked

@TypeChecked(extensions='SQLExtension.groovy') findAthletes(Sql sql) { sql.eachRow('select * frm Athlete') { row -> println row } }

SqlTC.groovy: 7: [Static type checking] - SQL query is not valid: net.sf.jsqlparser.JSQLParserException @ line 6, column 15. sql.eachRow('select * frm Athlete') { row -> println row } ^ 1 error Static compilation

import groovy.transform.* class Actor { String firstName, lastName

@CompileStatic String getFullName() { "$firstName $lastName" }

void makePeace() { new AntBuilder().('Peace was never an option') } } def magneto = new Actor(firstName: 'Ian', lastName: 'McKellen') assert magneto.fullName == 'Ian McKellen' magneto.makePeace() Static compilation speed

Fibonacci micro-benchmark

30

25

20

15

10

5

0 What makes Groovy Awesome? • Java integration • Scripting support • Multiparadigm • Gradual typing • Metaprogramming • Domain Specific Language support • Ecosystem • Community/Team Runtime metaprogramming

Awesome* – Add instance & static methods, constructors, properties at runtime – Intercept method/property access – Catch missing methods, properties – Used for dynamic builders, aspect- oriented programming, test stubs, mocks & dummies

* Individual levels of awesomeness may vary Runtime metaprogramming • Adding methods at runtime

assert 'Hello'.reverse() == 'olleH'

String..swapCase = { delegate.collect{ it in 'A'..'Z' ? it.toLowerCase() : it.toUpperCase() }.join() }

assert 'Hello'.swapCase() == 'hELLO' Runtime metaprogramming • Intercepting methods

class Foo { def one() { println "Called one()" } def methodMissing(String name, params) { println "Attempted $name($params)" } } Called one() Attempted two([]) def f = new Foo() Attempted three([Some Arg]) f.one() f.two() f.three('Some Arg') XML Parsing/GPath expressions

def = ''' ''' def hosts = new XmlParser().parseText(xml) assert hosts.host.service[0].@name=='MyMicroService' XML Parsing/GPath expressions

def xml = ''' ''' def hosts = new XmlParser().parseText(xml) assert hosts.host.service[0].@name=='MyMicroService' Compile-time metaprogramming

– Gives you the ability to Awesome change the language by augmenting the compilation process Compile-time metaprogramming • Modify the program at compile-time

@ToString class Person { String first, last

}

println new Person(first: 'John', last: 'Smith') // => Person(John, Smith) Compile-time metaprogramming • Modify the program at compile-time

class Person { String first, last String toString() { "Person($first, $last)" } }

println new Person(first: 'John', last: 'Smith') // => Person(John, Smith) Parsing Summary

MyScript.groovy

println "Howdy Y'all" > groovy MyScript.groovy > groovyc MyScript.groovy > groovysh > groovyConsole BlockStatement -> ReturnStatement public run() -> MethodCallExpression ... -> VariableExpression("this") L1 -> ConstantExpression("println") ALOAD 1 -> ArgumentListExpression LDC 1 -> ConstantExpression("Howdy Y'all") AALOAD ALOAD 0 LDC "Howdy Y'all" INVOKEINTERFACE callCurrent() ARETURN ... Parsing Summary

Initialization

Parsing • 9 phase compiler

Conversion – Early stages: read source code and convert into a Semantic Analysis sparse syntax tree Canonicalization – Middle stages:

Instruction Selection iteratively build up a more dense and Class Generation information rich version Output of the syntax tree Finalization – Later stages: check the tree and convert it into byte code/class files Parsing - Early Stages

Initialization @ToString Parsing class Greeter { String message = "Howdy Y'all" Conversion void greet() { println message Semantic Analysis } } Canonicalization ClassNode: Greeter MethodNode: greet Instruction Selection methods: BlockStatement MethodCall: this.println(message) Class Generation

properties: Property: message Output type: unresolved(String)

Finalization annotations: AnnotationNode: ToString type: unresolved(ToString) Parsing - Middle Stages

Initialization

Parsing

Conversion

ClassNode: Greeter Semantic Analysis MethodNode: greet methods: Canonicalization MethodNode: getMessage

MethodNode: setMessage Instruction Selection MethodNode: toString

Class Generation MethodNode: getMetaClass … Output fields: FieldNode: message type: resolved(String) Finalization constructors: ConstructorNode 103 Parsing - Final Stages

Initialization

Parsing

Conversion

Semantic Analysis

Canonicalization public greet()V ... Instruction Selection L1 ... Class Generation ALOAD 0 GETFIELD Greeter.message Output INVOKEINTERFACE callCurrent() POP Finalization ... Immutable Classes • Some Rules – Don’t provide mutators – Ensure that no methods can be overridden • Easiest to make the class final • Or use static factories & non-public constructors – Make all fields final – Make all fields private • Avoid even public immutable constants – Ensure exclusive access to any mutable components • Don’t leak internal references • Defensive copying in and out – Optionally provide equals and hashCode methods – Optionally provide toString method @Immutable... • Java Immutable Class

– As per Joshua Bloch // ... @Override Effective Java public boolean equals(Object obj) { if (this == obj) public final class Person { return true; private final String first; if (obj == null) private final String last; return false; if (getClass() != obj.getClass()) public String getFirst() { return false; return first; Person other = (Person) obj; } if (first == null) { if (other.first != null) public String getLast() { return false; return last; } else if (!first.equals(other.first)) } return false; if (last == null) { @Override if (other.last != null) public int hashCode() { return false; final int prime = 31; } else if (!last.equals(other.last)) int result = 1; return false; result = prime * result + ((first == null) return true; ? 0 : first.hashCode()); } result = prime * result + ((last == null) ? 0 : last.hashCode()); @Override return result; public String toString() { } return "Person(first:" + first + ", last:" + last + ")"; public Person(String first, String last) { } this.first = first; this.last = last; } } // ...... @Immutable... • Java Immutable Class boilerplate

– As per Joshua Bloch // ... @Override Effective Java public boolean equals(Object obj) { if (this == obj) public final class Person { return true; private final String first; if (obj == null) private final String last; return false; if (getClass() != obj.getClass()) public String getFirst() { return false; return first; Person other = (Person) obj; } if (first == null) { if (other.first != null) public String getLast() { return false; return last; } else if (!first.equals(other.first)) } return false; if (last == null) { @Override if (other.last != null) public int hashCode() { return false; final int prime = 31; } else if (!last.equals(other.last)) int result = 1; return false; result = prime * result + ((first == null) return true; ? 0 : first.hashCode()); } result = prime * result + ((last == null) ? 0 : last.hashCode()); @Override return result; public String toString() { } return "Person(first:" + first + ", last:" + last + ")"; public Person(String first, String last) { } this.first = first; this.last = last; } } // ...... @Immutable

@Immutable class Person { String first, last }

Awesome With Macros (coming in 2.5) import org.codehaus.groovy.ast.* import org.codehaus.groovy.ast.stmt.* import org.codehaus.groovy.ast.expr.* def ast = new ReturnStatement( new ConstructorCallExpression( ClassHelper.make(Date), ArgumentListExpression.EMPTY_ARGUMENTS ) )

def ast = macro { Awesome new Date() } Macro examples (coming in 2.5) Adapted from https://github.com/touchez-du-bois/akatsuki • nullSafe but adapted for the experimental Antlr4 “Parrot” parser.

class X { String name } def getName(Z z) { class Y { z.y.list[0].name List list } }

class Z { Y y } Macro examples (coming in 2.5) Adapted from https://github.com/touchez-du-bois/akatsuki • nullSafe but adapted for the experimental Antlr4 “Parrot” parser.

class X { String name } def getName(Z z) { class Y { z.y.list[0].name List list } }

class Z { Y y } Macro examples (coming in 2.5) Adapted from https://github.com/touchez-du-bois/akatsuki • nullSafe but adapted for the experimental Antlr4 “Parrot” parser.

class X { String name } def getName(Z z) { class Y { z.y.list[0].name List list } }

class Z { Y y } Prone to NPE Macro examples (coming in 2.5) Adapted from https://github.com/touchez-du-bois/akatsuki • nullSafe but adapted for the experimental Antlr4 “Parrot” parser. class X { String name } class Y {def getName(Z z) { List listdef result = null } if (z != null && z.y != null && z.y.list != null && z.y.list[0] != null) { class Z { result = z.y.list[0].name Y y } } result } Macro examples (coming in 2.5) Adapted from https://github.com/touchez-du-bois/akatsuki • nullSafe but adapted for the experimental Antlr4 “Parrot” parser. class X { String name } class Y {def getName(Z z) { List listdef result = null } if (z != null && z.y != null && z.y.list != null && z.y.list[0] != null) { class Z { result = z.y.list[0].name Y y } } result }

Verbose Macro examples (coming in 2.5) Adapted from https://github.com/touchez-du-bois/akatsuki but adapted for the experimental Antlr4 “Parrot” parser. class X { String name def getName(Z z) { } z?.y?.list?[0]?.name class Y { } List list } class Z { Y y } Macro examples (coming in 2.5) Adapted from https://github.com/touchez-du-bois/akatsuki but adapted for the experimental Antlr4 “Parrot” parser. class X { String name def getName(Z z) { } nullSafe(z.y.list[0].name) class Y { } List list } class Z { Adds in the’?’ automatically Y y } Macro examples (coming in 2.5)

See: https://github.com/touchez-du-bois/akatsuki

def fact(num) { return match(num) { when String then fact(num.toInteger()) when(0 | 1) then 1 when 2 then 2 orElse num * fact(num - 1) } } assert fact("5") == 120 Macro examples (coming in 2.5) • Spock inspired

@Grab('org.spockframework:spock-core:1.0-groovy-2.4') import spock.lang.Specification

class MathSpec extends Specification { def "maximum of two numbers"(int a, int b, int c) { : Math.max(a, b) == c

where: a | b | c 1 | 3 | 3 7 | 4 | 7 0 | 0 | 0 } } Macro examples (coming in 2.5)

See: https://github.com/touchez-du-bois/akatsuki

doWithData { dowith: assert a + b == c where: a | b || c 1 | 2 || 3 4 | 5 || 9 7 | 8 || 15 } What makes Groovy Awesome? • Java integration • Scripting support • Multiparadigm • Gradual typing • Metaprogramming • Domain Specific Language support – Command chains – Various examples • Ecosystem • Community/Team Command Chains • Ability to chain method calls without parentheses and dots

Awesome Command Chains • Ability to chain method calls without parentheses and dots

move forward at 3.km/h Command Chains • Ability to chain method calls without parentheses and dots

move forward at 3.km/h

• Equivalent to:

move(forward).at(3.getKm().div(h)) Command chains in DSLs

Number.metaClass.getShares = { delegate } Number.metaClass.getDollars = { delegate }

String GOOG = 'Google' def sell(int nShares) { [of: { String ticker -> [at: { int price -> println "Sold $nShares $ticker at \$$price" }] }] } sell 100.shares of GOOG at 1000.dollars Command chains in DSLs show = { println it } square_root = { Math.sqrt(it) } def please(action) { [the: { what -> [of: { n -> action(what(n)) }] }] } please show the square_root of 100 // ==> 10.0 Command chains in DSLs show = { println it } square_root = { Math.sqrt(it) } def please(action) { [the: { what -> [of: { n -> action(what(n)) }] }] } please(show).the(square_root).of(100) // ==> 10.0 Command chains in DSLs show = { println it } square_root = { Math.sqrt(it) } def please(action) { [the: { what -> [of: { n -> action(what(n)) }] }] } please(show).the(square_root).of(100) // ==> 10.0

… and again in another language … Command chains in DSLs

// Japanese DSL Object.metaClass.を = Object.metaClass.の = { clos -> clos(delegate) }

まず = { it } 表示する = { println it } 平方根 = { Math.sqrt(it) }

まず 100 の 平方根 を 表示する // First, show the square root of 100

// => 10.0 // source: http://d.hatena.ne.jp/uehaj/20100919/1284906117 // http://groovyconsole.appspot.com/edit/241001 Logic programming example

cranes have 2 legs tortoises have 4 legs there are 7 animals there are 20 legs

How many of each animal? Recall: Constraint programming example

ChocoCraneTortoise.groovy @Grab('org.choco-solver:choco-solver:4.0.0') import org.chocosolver.solver.Model def m = new Model() def totalAnimals = 7 def totalLegs = 20 def numCranes = m.intVar('Cranes', 0, totalAnimals, true) def numTortoises = m.intVar('Tortoises', 0, totalAnimals, true) def numCraneLegs = m.intScaleView(numCranes, 2) def numTortoiseLegs = m.intScaleView(numTortoises, 4) m.arithm(numCranes, '+', numTortoises, '=', totalAnimals).post() m.arithm(numCraneLegs, '+', numTortoiseLegs, '=', totalLegs).post() if (m.solver.solve()) println "$numCranes\n$numTortoises" else println "No Solutions" Cranes = 4 Tortoises = 3 Logic programming example

dslUntyped/ChocoCraneTortoiseDSL.groovy 50 lines to define the DSL Logic programming example

dslUntyped/ChocoCraneTortoiseDSL.groovy 50 lines to define the DSL cranes have 2 legs tortoises have 4 legs there are 7 animals there are 20 legs display solution

Cranes 4 Tortoises 3 Logic programming example

dslUntyped/ChocoCraneTortoiseDSL.groovy 50 lines to define the DSL cranes have 2 legs tortoises have 4 legs millipedes have 1000 legs there are 8 animals there are 1020 legs display solution

Cranes 4 Tortoises 3 Millipedes 1 Logic programming example

dslTyped/ChocoCraneTortoiseDSL.groovy 80 lines to define the DSL

@TypeChecked def main() { animals seen include Crane, Tortoise, Beetle, Centipede leg count is 150 head count is 26 display solution }

Solution: Tortoise = 3, Beetle = 23 Solution: Crane = 1, Tortoise = 1, Beetle = 24 Solution: Crane = 25, Centipede = 1 Logic programming example

dslTyped/ChocoCraneTortoiseDSL.groovy 80 lines to define the DSL

@TypeChecked def main() { animals seen include Crane, Tortoise, Beetle, Centipede leg count is 150 head count is 26 display solution } DSL Type Provider unresolvedVariable { var -> if (!cachedAnimalNames) { def accessKey = '72ddf45a-c751-44c7-9bca-8db3b4513347' // for illustrative purposes, just download xml for a few animals def uid = 'ELEMENT_GLOBAL.2.104550,ELEMENT_GLOBAL.2.105196,ELEMENT_GLOBAL.2.120227' def base = "https://services.natureserve.org/idd/rest/ns/v1.1/globalSpecies" def url = "$base/comprehensive?uid=$uid&NSAccessKeyId=$accessKey" def root = new XmlParser().parse(url) def names = root.globalSpecies.classification.names cachedAnimalNames = names.natureServePrimaryGlobalCommonName*.text()*.replaceAll(' ','') } if (var.name in cachedAnimalNames) { storeType(var, STRING_TYPE) handled = true enclosingClassNode.addField(var.name, 0, STRING_TYPE, new ConstantExpression(var.name)) } } DSL Type Provider

provider/ChocoCraneTortoiseProvider.groovy Custom checker 80 lines to define the DSL 25 lines to define the provider

@TypeChecked(extensions='NatureServeAnimalProvider.groovy') def main() { animals seen include SandhillCrane, GopherTortoise, ChihuahuanMillipede leg count is 1020 head count is 8 display solution } Ecosystem

Awesome Awesome

Awesome Awesome Awesome Team Awesome Groovy's

© ASERT 2006-2016 Awesome Team Awesome Groovy's

© ASERT 2006-2016

qtrs

Direct downloads: Direct million3 approx. 2013: million 4+ 2014: 3 first in million 7+ 2015: Awesome Team Awesome Groovy's +100's of others

© ASERT 2006-2016

Awesome Team Awesome just like like just YOU! Groovy's +100's of others

© ASERT 2006-2016 © ASERT 2006-2016 More Information: Groovy in Action

Awesome Bonus Material

© ASERT 2006-2016 145 Audience Puzzle • There are 6 heads • There are 14 legs 146 Audience Puzzle • There are 6 heads • There are 14 legs 147 Other solution • There are 6 heads • There are 14 legs 148 Other solution • There are 6 heads • There are 14 legs Functional style class RecursiveCalc {

int accumulate(int n) { n <= 0 ? 0 : n + accumulate(n - 1) } } Functional style class RecursiveCalc {

int accumulate(int n, int sum = 0) { (n <= 0) ? sum : accumulate(n - 1, sum + n) } } Functional style class RecursiveCalc { @TailRecursive int accumulate(int n, int sum = 0) { (n <= 0) ? sum : accumulate(n - 1, sum + n) } } Functional style class RecursiveCalc { @TailRecursive int accumulate(int n, int sum = 0) { (n <= 0) ? sum : accumulate(n - 1, sum + n) } }

class RecursiveCalc { int accumulate(int n, int sum) { int _sum_ = sum int _n_ = n while (true) { if (_n_ <= 0) { return _sum_ } else { int __n__ = _n_ int __sum__ = _sum_ _n_ = __n__ - 1 _sum_ = __sum__ + __n__ } } } int accumulate(int n) { accumulate(n, 0) } } Functional style class RecursiveCalc { @TailRecursive int accumulate(int n, int sum = 0) { (n <= 0) ? sum : accumulate(n - 1, sum + n) } } class RecursiveCalc { int accumulate(int n, int sum) { int _sum_ = sum int _n_ = n while (true) { if (_n_ <= 0) { return _sum_ } else { int __n__ = _n_ int __sum__ = _sum_ _n_ = __n__ - 1 _sum_ = __sum__ + __n__ } } } int accumulate(int n) { accumulate(n, 0) } } Builders and phantom types

@Immutable @Builder(builderStrategy=InitializerStrategy) class Person { String first String last © ASERT 2006 ASERT © int age

}

- 2016 @CompileStatic def main() { println new Person(Person.createInitializer() .first("John").last("Smith").age(21)) } GPars actors def decryptor = actor { loop { react { message -> if (message instanceof String) reply message.reverse() else stop() } © ASERT 2006 ASERT © }

} - 2016 def console = actor { decryptor.send 'lellarap si yvoorG' react { println "Decrypted message: $it" decryptor.send false } }

[decryptor, console]*.join() Image credits • http://www.foodclipart.com/food_clipart_images/chocolate_cake_with_vanilla_frosting_0071- 0903-1511-3326. • Mars photo credit: These long streaks are inferred to have been formed by contemporary flowing water. NASA/JPL/University of Arizona • https://www.flickr.com/photos/skoop102/29656746824/in/pool-parrotsparrotsparrots/