SlideShare ist ein Scribd-Unternehmen logo
1 von 151
Downloaden Sie, um offline zu lesen
Dr Paul King
Groovy Lead for Object Computing Inc.
@paulk_asert
http:/slideshare.net/paulk_asert/awesome-groovy
https://github.com/paulk-asert/awesome-groovy
Apache Groovy:
The Awesome Parts
FRIEND OF GROOVY
Part 1: Introducing Groovy?
What is Groovy?
4
Groovy = Java – boiler plate code
+ closures (1st class FP)
+ extensible type system
+ runtime & compile-time metaprogramming
+ flexible language grammar (DSLs)
+ scripting
+ GDK library
“Groovy is like a super version of Java.
It leverages Java features but adds productivity features
and provides great flexibility and extensibility.”
Why Groovy?
Java
Why Groovy?
Too verbose
Support
functional
programming
Better
concurrency
Evolves
too slowly
I need
feature
XXX
Too complex
for some
situations
More
flexibility
Java
Why Groovy?
Groovy
Make it
simplerMake it
dynamic
Support
simple
scripting
Why Groovy?
Groovy
Make it
simplerMake it
dynamic
Support
simple
scripting
Java
integration
Why Groovy?
Groovy
Make it
simplerMake it
dynamic
Support
simple
scripting
Good IDE
support
Java
integration
Why Groovy?
Groovy
Make it
simplerMake it
dynamic
Support
simple
scripting
Good IDE
support
Custom
features
Java
integration
Why Groovy?
Groovy
Make it
simplerMake it
dynamic
Support
simple
scripting
Support
concurrency
Good IDE
support
Custom
features
Java
integration
Why Groovy?
Groovy
Make it
simplerMake it
dynamic
Support
simple
scripting
Support
functional
style
Support
concurrency
Good IDE
support
Custom
features
Java
integration
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);
}
}
return result;
}
public static void main(String[] args) {
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);
if (s.length() < length) {
result.add(s);
}
}
return result;
}
public static void main(String[] args) {
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);
}
}
}
Rename
Main.java
to
Main.groovy
Some Java Boilerplate identified
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);
}
}
return result;
}
public static void main(String[] args) {
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);
}
}
}
Are the semicolons
needed?
And shouldn’t
we us more
modern list
notation?
Why not
import common
libraries?
Do we need
the static types?
Must we always
have a main
method and
class definition?
How about
improved
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
}
names = new ArrayList()
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) {
def result = new ArrayList()
for (s in strings) {
if (s.size() < length) {
result.add(s)
}
}
return result
}
names = new ArrayList()
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)
}
Shouldn’t we
have special
notation for lists?
And special
facilities for
list processing?
Is ‘return’
needed at end?
Is the method
now needed?
Simplify common
methods?
Remove unambiguous
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 }
["Ted", "Fred", "Jed", "Ned"]
3
Ted
Jed
Ned
Output:
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
// plus a DSL implementation
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
names = []
def of, having, less
def given(_the) { [names:{ Object[] ns -> names.addAll(ns)
[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
• Or use GDSL (IntelliJ IDEA) or DSLD (Eclipse)
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
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
…
enum The { the }
enum Having { having }
enum Of { of }
…
class DisplayThe {
DisplayTheNamesHaving names(Having having) {
new DisplayTheNamesHaving()
}
DisplayTheNumberOf number(Of of) {
new DisplayTheNumberOf()
}
}
…
// plus 50 lines
Or typed Groovy DSL version if required
Groovy DSL being debugged
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
}
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
}
afterMethodCall { mc ->
mc.arguments.each {
if (isConstantExpression(it)) {
if (it.value instanceof String && !it.value.endsWith('ed')) {
addStaticTypeError("I don't like the name '${it.value}'", mc)
}
}
}
}

@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
}
Or typed Groovy DSL version if required
afterMethodCall { mc ->
mc.arguments.each {
if (isConstantExpression(it)) {
if (it.value instanceof String && !it.value.endsWith('ed')) {
addStaticTypeError("I don't like the name '${it.value}'", mc)
}
}
}
}
@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
}
afterMethodCall { mc ->
mc.arguments.each {
if (isConstantExpression(it)) {
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
}
afterMethodCall { mc ->
mc.arguments.each {
if (isConstantExpression(it)) {
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

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
Part 2: What makes Groovy Awesome?
What makes Groovy Awesome?
• Java integration
• Scripting support
• Multiparadigm
• Gradual typing
• Metaprogramming
• Domain specific
language (DSL) support
• Ecosystem
• Community/Team
Awesome
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
Java
Groovy
Java Integration
• Standing on the shoulders of Giants
• Some limitations inherited but much
gained through new releases of Java
• Rock solid foundation
• Can ease migration to new versions
of Java
Java
Groovy
Java Integration
• Seamless integration
• IDEs provide cross-language compile,
navigation, and refactoring
• Arbitrarily mix source language
• Drop-in replace
any class
• Overloaded methods
• Syntax alignment
• Shared data types
Java
Groovy
Java Integration
• Seamless integration
• IDEs provide cross-language compile,
navigation, and refactoring
• Arbitrarily mix source language
• Drop-in replace
any class
• Overloaded methods
• Syntax alignment
• Shared data types
Java
Groovy
Java Integration
• Polyglot friendly
• Typically integrates well with other
languages which integrate with Java
• JRuby
• Jython
• Scala
• Frege
• Clojure
• R through Renjin
• JavaScript
(Rhino/Nashorn)
Java Integration
• Polyglot friendly
• JSR-223 scripting
to talk to JavaScript
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
GroovyJavaScript
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) {
y <- 1
for (i in 1:x) { y <- y * i }
return(y)
}
'''
assert eval('factorial(4)')[0] == 24
}
Java
GroovyR
Grooscript
@Grab('org.grooscript:grooscript:1.2.0')
import org.grooscript.GrooScript
import javax.script.ScriptEngineManager
def groojs = GrooScript.convert '''
def sayHello = { println "Hello ${it}!" }
['Groovy','JavaScript','GrooScript'].each sayHello''',
[initialText: 'var console = { log: print }',
addGsLib: 'grooscript.min']
new ScriptEngineManager().getEngineByName("nashorn").eval(groojs)
Hello Groovy!
Hello JavaScript!
Hello GrooScript!
Jorge Franco, grooscript.org
Convert Groovy subset to JavaScript
Support: Gradle, Grails, NPM
Demos: react.js, node.js, Pollock
Converts: Classes, closures, Date
primitives, ranges, String/GString
Special: builder, templates, gQuery
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
Awesome
• Friend of Java
• Integration
• Good JVM Citizen
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
Awesome
Scripting
• Terse format
• Isolation
• Domain-Specific
Languages (DSLs)
• Security
• Flexibility
Scripting
• Leave out surrounding class
• Entire source file:
public class Script {
public static void main(String[] args) {
System.out.println("Hello world");
}
}
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
move left
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
Scripting
move left
def robot = new Robot()
def binding = new Binding(/* ... */)
def imports = new ImportCustomizer().addStaticStars('java.lang.Math')
def timeout = new ASTTransformationCustomizer(value: 2, TimedInterrupt)
def secure = new SecureASTCustomizer().with {
closuresAllowed = false
importsWhitelist = []
tokensWhitelist = [ PLUS, MINUS, MULTIPLY, DIVIDE, /*...*/ ]
//...
}
def sysExit = new CompilationCustomizer(CANONICALIZATION) {
void call(SourceUnit src, GeneratorContext ctxt, ClassNode cn) {
new ClassCodeVisitorSupport() {
void visitMethodCallExpression(MethodCallExpression call) {
// check for System.exit()
}
// ...
}.visitClass(cn)
}
}
def config = new CompilerConfiguration()
config.addCompilationCustomizers(imports, timeout, secure, sysExit)
def shell = new GroovyShell(binding, config)
Scripting
move left
move forward at 3.km/h
More
examples
later
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
Awesome
• Simpler scripting
• Separation of concerns
What makes Groovy Awesome?
• Java integration
• Scripting support
• Multiparadigm
• Object-oriented
• Functional, Closures
• Logic/Dataflow programming
• Gradual typing
• Metaprogramming
• Domain Specific Language support
• Ecosystem
• Community/Team
Multiparadigm
• Imperative roots from Java
• OO abstractions: classes,
interfaces, inheritance
• Properties
• Traits
• First class functional support via closures
• External libraries for advanced features
• Other paradigms via libraries
• Logic, dataflow, reactive
Awesome
Multiparadigm
Imperative/OO
Logic programming
Functional
Rich 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
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!"
Rich functional features
• Closures
• First-class functions
• Higher-order functions
• Map, reduce, filter
• Mutable & immutable data
• Recursion
• Lazy & eager evaluation
• Advanced FP techniques
• Memoization, Trampolines, Composition, Curry
• Concurrency
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 (+ functional style)
@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'
def young = { person, threshold ->
person.age < threshold
}.rcurry(40).memoize()
assert people
.findAll(young)
.collect{ it.name.toUpperCase() }
.sort()
.join(', ') == 'MARY, PAUL'
map/filter/reduce (+ with streams)
@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'
// requires JRE 8
def commaSep = Collectors.joining(", ")
assert people.stream()
.filter{ it.age < 40 }
.map{ it.name.toUpperCase() }
.sorted()
.collect(commaSep) == 'MARY, PAUL'
Logic/Constraint programming
• Logic programming
• Declarative style
• Logic clauses for example Prolog
• 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
@Grab('org.choco-solver:choco-solver:4.0.4')
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 "$numCranesn$numTortoises"
else
println "No Solutions" Cranes = 4
Tortoises = 3
ChocoCraneTortoise.groovy
See also: JSR-331 Constraint Programming API
Dataflow programming
• 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
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 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
72
Awesome
Concurrency challenge
• We can analyse the example’s task graph:
def (f1, f2, f3, f4) = [{ sleep 1000; it }] * 3 +
[{ x, y -> x + y }]
def a = 5
def b = f1(a)
def c = f2(a)
def d = f3(c)
def f = f4(b, d)
assert f == 10
Concurrency challenge
• We can analyse the example’s task graph:
def (f1, f2, f3, f4) = [{ sleep 1000; it }] * 3 +
[{ x, y -> x + y }]
def a = 5
def b = f1(a)
def c = f2(a)
def d = f3(c)
def f = f4(b, d)
assert f == 10
f2
f3
f1
f4
aa
b
c
d
f
Concurrency challenge
• Manually using asynchronous functions:
def (f1, f2, f3, f4) = [{ sleep 1000; it }] * 3 +
[{ x, y -> x + y }]
import static groovyx.gpars.GParsPool.withPool
withPool(2) {
def a = 5
def futureB = f1.callAsync(a)
def c = f2(a)
def d = f3(c)
def f = f4(futureB.get(), d)
assert f == 10
}
f2
f3
f1
f4
aa
futureB
c
d
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
new Dataflows().with {
task { a = 5 }
task { b = f1(a) }
task { c = f2(a) }
task { d = f3(c) }
task { f = f4(b, d) }
assert f == 10
}
f2
f3
f1
f4
aa
b
c
d
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
new Dataflows().with {
task { f = f4(b, d) }
task { d = f3(c) }
task { c = f2(a) }
task { b = f1(a) }
task { a = 5 }
assert f == 10
}
f2
f3
f1
f4
aa
b
c
d
f
What makes Groovy Awesome?
• Java integration
• Scripting support
• Multiparadigm
• Object-oriented
• Functional, Closures
• Logic/dataflow programming
• Gradual typing
• Metaprogramming
• Domain Specific Language support
• Ecosystem
• Community/Team
• Ability to use imperative
when needed for speed
• Numerous declarative
approaches available
when it makes sense
Awesome
What makes Groovy Awesome?
• Java integration
• Scripting support
• Multiparadigm
• Gradual typing
• Dynamic strong typing
• Static type checking
• Extensible
• Type inference
• Metaprogramming
• Domain Specific Language support
• Ecosystem
• Community/Team
Gradual typing
• Dynamic by default
• Gradual typing
• Static type checking
• Extensible type system
Awesome
Dynamic vs static
82
def myPets = ['Lassie', 'Skip']
List<String> yourPets = ['Lassie', 'Skip']
shouldFail(ClassCastException) {
List ourPets = new Date()
}
Dynamic vs static
83
Gradual
Type-time?
def myPets = ['Lassie', 'Skip']
List<String> yourPets = ['Lassie', 'Skip']
shouldFail(ClassCastException) {
List ourPets = new Date()
}
Dynamic vs static
84
def myPets = ['Lassie', 'Skip']
List<String> yourPets = ['Lassie', 'Skip']
shouldFail(ClassCastException) {
List ourPets = new Date()
}
def adder = { a, b -> a + b }
assert adder(100, 200) == 300
assert adder('X', 'Y') == 'XY'
Dynamic vs static
85
def adder = { a, b -> a + b }
assert adder(100, 200) == 300
assert adder('X', 'Y') == 'XY'
def myPets = ['Lassie', 'Skip']
List<String> yourPets = ['Lassie', 'Skip']
shouldFail(ClassCastException) {
List ourPets = new Date()
}
Duck-typing
Dynamic vs static
86
def adder = { a, b -> a + b }
assert adder(100, 200) == 300
assert adder('X', 'Y') == 'XY'
def myPets = ['Lassie', 'Skip']
List<String> yourPets = ['Lassie', 'Skip']
shouldFail(ClassCastException) {
List ourPets = new Date()
}
@TypeChecked
def myMethod() {
def myPets = ['Lassie', 'Skip']
List yourPets = ['Lassie', 'Skip']
}
shouldFail(CompilationFailedException) {
assertScript '''
@groovy.transform.TypeChecked
def yourMethod() {
List ourPets = new Date()
}
'''
}
Dynamic vs static
87
def adder = { a, b -> a + b }
assert adder(100, 200) == 300
assert adder('X', 'Y') == 'XY'
def myPets = ['Lassie', 'Skip']
List<String> yourPets = ['Lassie', 'Skip']
shouldFail(ClassCastException) {
List ourPets = new Date()
}
@TypeChecked
def myMethod() {
def myPets = ['Lassie', 'Skip']
List yourPets = ['Lassie', 'Skip']
}
shouldFail(CompilationFailedException) {
assertScript '''
@groovy.transform.TypeChecked
def yourMethod() {
List ourPets = new Date()
}
'''
}
Extensible
Inference
Extensible type checking
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'
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.
Extensible type checking
import groovy.sql.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().echo('Peace was never an option')
}
}
def magneto = new Actor(firstName: 'Ian', lastName: 'McKellen')
assert magneto.fullName == 'Ian McKellen'
magneto.makePeace()
Static compilation speed
0
5
10
15
20
25
30
Fibonacci micro-benchmark
What makes Groovy Awesome?
• Java integration
• Scripting support
• Multiparadigm
• Gradual typing
• Dynamic strong typing
• Static type checking
• Extensible
• Type inference
• Metaprogramming
• Domain Specific Language support
• Ecosystem
• Community/Team
• Maximise duck-typing
• Minimise noise
• yet type inference
• Flexibility at runtime
• As strict as you want
when needed
• Fast when needed
Awesome
What makes Groovy Awesome?
• Java integration
• Scripting support
• Multiparadigm
• Gradual typing
• Metaprogramming
• Runtime
• Compile-time
• Macros
• Domain Specific Language support
• Ecosystem
• Community/Team
Runtime metaprogramming
• 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
Awesome*
* Individual levels of awesomeness may vary
Runtime metaprogramming
• Adding methods at runtime
assert 'Hello'.reverse() == 'olleH'
String.metaClass.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)"
}
}
def f = new Foo()
f.one()
f.two()
f.three('Some Arg')
Called one()
Attempted two([])
Attempted three([Some Arg])
XML Parsing/GPath expressions
def xml = '''
<hosts>
<host name='MyHost'>
<service name='MyMicroService'/>
<service name='MyNanoService'/>
</host>
</hosts>
'''
def hosts = new XmlParser().parseText(xml)
assert hosts.host.service[0].@name=='MyMicroService'
def xml = '''
<hosts>
<host name='MyHost'>
<service name='MyMicroService'/>
<service name='MyNanoService'/>
</host>
</hosts>
'''
def hosts = new XmlParser().parseText(xml)
assert hosts.host.service[0].@name=='MyMicroService'
XML Parsing/GPath expressions
Compile-time metaprogramming
• Gives you the ability to change the language by augmenting the
compilation process
Awesome
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
public run()
...
L1
ALOAD 1
LDC 1
AALOAD
ALOAD 0
LDC "Howdy Y'all"
INVOKEINTERFACE callCurrent()
ARETURN
...
println "Howdy Y'all"
BlockStatement
-> ReturnStatement
-> MethodCallExpression
-> VariableExpression("this")
-> ConstantExpression("println")
-> ArgumentListExpression
-> ConstantExpression("Howdy Y'all")
MyScript.groovy
> groovy MyScript.groovy
> groovyc MyScript.groovy
> groovysh
> groovyConsole
• 9 phase compiler
– Early stages: read source code
and convert into a sparse syntax
tree
– Middle stages: iteratively build up
a more dense and information rich
version of the syntax tree
– Later stages: check the tree and
convert it into byte code/class files
Initialization
Semantic Analysis
Instruction Selection
Parsing
Conversion
Canonicalization
Class Generation
Output
Finalization
Parsing Summary
Parsing - Early Stages
Initialization
Semantic Analysis
Instruction Selection
Parsing
Conversion
Canonicalization
Class Generation
Output
Finalization
@ToString
class Greeter {
String message = "Howdy Y'all"
void greet() {
println message
}
}
ClassNode: Greeter
MethodNode: greet
Property: message
type: unresolved(String)
AnnotationNode:
ToString
type:
unresolved(ToString)
methods:
properties:
annotations:
BlockStatement
MethodCall:
this.println(message)
Parsing - Middle Stages
Initialization
Semantic Analysis
Instruction Selection
Parsing
Conversion
Canonicalization
Class Generation
Output
Finalization
ClassNode: Greeter
MethodNode: greet
FieldNode: message
type: resolved(String)
methods:
fields:
constructors:
ConstructorNode
MethodNode:
getMessageMethodNode:
setMessageMethodNode: toString
MethodNode:
getMetaClass…
Parsing - Final Stages
106
Initialization
Semantic Analysis
Instruction Selection
Parsing
Conversion
Canonicalization
Class Generation
Output
Finalization
public greet()V
...
L1
...
ALOAD 0
GETFIELD Greeter.message
INVOKEINTERFACE callCurrent()
POP
...
Immutable Classes
• Some Rules
• Don’t provide mutators
• Ensure that no methods can
be overridden
o Easiest to make the class final
o Or use static factories & non-public
constructors
• Make all fields final
• Make all fields private
o Avoid even public immutable constants
• Ensure exclusive access to any mutable components
o Don’t leak internal references
o Defensive copying in and out
• Optionally provide equals and hashCode methods
• Optionally provide toString method
@Immutable...
• Java Immutable Class
• As per Joshua Bloch Effective Java
public final class Person {
private final String first;
private final String last;
public String getFirst() {
return first;
}
public String getLast() {
return last;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((first == null)
? 0 : first.hashCode());
result = prime * result + ((last == null)
? 0 : last.hashCode());
return result;
}
public Person(String first, String last) {
this.first = first;
this.last = last;
}
// ...
// ...
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (first == null) {
if (other.first != null)
return false;
} else if (!first.equals(other.first))
return false;
if (last == null) {
if (other.last != null)
return false;
} else if (!last.equals(other.last))
return false;
return true;
}
@Override
public String toString() {
return "Person(first:" + first
+ ", last:" + last + ")";
}
}
...@Immutable...
public final class Person {
private final String first;
private final String last;
public String getFirst() {
return first;
}
public String getLast() {
return last;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((first == null)
? 0 : first.hashCode());
result = prime * result + ((last == null)
? 0 : last.hashCode());
return result;
}
public Person(String first, String last) {
this.first = first;
this.last = last;
}
// ...
// ...
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (first == null) {
if (other.first != null)
return false;
} else if (!first.equals(other.first))
return false;
if (last == null) {
if (other.last != null)
return false;
} else if (!last.equals(other.last))
return false;
return true;
}
@Override
public String toString() {
return "Person(first:" + first
+ ", last:" + last + ")";
}
}
boilerplate• Java Immutable Class
• As per Joshua Bloch Effective Java
...@Immutable
@Immutable class Person {
String first, last
}
Awesome
With Macros (Groovy 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 {
return new Date()
}
With Macros (Groovy 2.5+)
Awesome
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 {
return new Date()
}
With Macros (Groovy 2.5+)
• Variations:
• Expressions, Statements, Classes
• Supports variable substitution,
specifying compilation phase
def ast = macro {
return new Date()
}
With Macros (Groovy 2.5+)
• AST Matching:
• Selective transformations, filtering, testing
• Supports placeholders
Expression transform(Expression exp) {
Expression ref = macro { 1 + 1 }
if (ASTMatcher.matches(ref, exp)) {
return macro { 2 }
}
return super.transform(exp)
}
Macro method examples
class X {
String name
}
class Y {
List<X> list
}
class Z {
Y y
}
Adapted from https://github.com/touchez-du-bois/akatsuki
but adapted for the experimental Antlr4 “Parrot” parser.
def getName(Z z) {
z.y.list[0].name
}
• nullSafe
Macro method examples
class X {
String name
}
class Y {
List<X> list
}
class Z {
Y y
}
def getName(Z z) {
z.y.list[0].name
}
Adapted from https://github.com/touchez-du-bois/akatsuki
but adapted for the experimental Antlr4 “Parrot” parser.
• nullSafe
Macro method examples
class X {
String name
}
class Y {
List<X> list
}
class Z {
Y y
}
def getName(Z z) {
z.y.list[0].name
}
Prone to NPE
Adapted from https://github.com/touchez-du-bois/akatsuki
but adapted for the experimental Antlr4 “Parrot” parser.
• nullSafe
Macro method examples
• nullSafe
class X {
String name
}
class Y {
List<X> list
}
class Z {
Y y
}
def getName(Z z) {
def result = null
if (z != null && z.y != null &&
z.y.list != null && z.y.list[0] != null) {
result = z.y.list[0].name
}
result
}
Adapted from https://github.com/touchez-du-bois/akatsuki
but adapted for the experimental Antlr4 “Parrot” parser.
Macro method examples
class X {
String name
}
class Y {
List<X> list
}
class Z {
Y y
}
def getName(Z z) {
def result = null
if (z != null && z.y != null &&
z.y.list != null && z.y.list[0] != null) {
result = z.y.list[0].name
}
result
}
Verbose
Adapted from https://github.com/touchez-du-bois/akatsuki
but adapted for the experimental Antlr4 “Parrot” parser.
• nullSafe
Macro method examples
def getName(Z z) {
z?.y?.list?[0]?.name
}
class X {
String name
}
class Y {
List<X> list
}
class Z {
Y y
}
Adapted from https://github.com/touchez-du-bois/akatsuki
but adapted for the experimental Antlr4 “Parrot” parser.
• nullSafe
class X {
String name
}
class Y {
List<X> list
}
class Z {
Y y
}
Macro method examples
Adapted from https://github.com/touchez-du-bois/akatsuki
but adapted for the experimental Antlr4 “Parrot” parser.
• nullSafe
def getName(Z z) {
nullSafe(z.y.list[0].name)
}
Macro method examples
@Macro
static Expression nullSafe(MacroContext macroContext, Expression expression) {
if (expression instanceof PropertyExpression) {
// exp.prop -> exp?.prop …
} else if (expression instanceof MethodCallExpression) {
// exp.method() -> exp?.method() …
}
return expression
}
• nullSafe
def getName(Z z) {
nullSafe(z.y.list[0].name)
}
Macro method examples
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
See: https://github.com/touchez-du-bois/akatsuki
Macro method examples
• 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) {
expect:
Math.max(a, b) == c
where:
a | b | c
1 | 3 | 3
7 | 4 | 7
0 | 0 | 0
}
}
Macro method examples
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
• Runtime
• Compile-time
• Macros
• Domain Specific Language support
• Ecosystem
• Community/Team
• Ability to change the language
at runtime
• Ability to change the language
during the compilation process
• Macros provide a
homogeneous form
for writing AST
transformations
Awesome
Part 2: What makes Groovy Awesome?
• Java integration
• Scripting support
• Multiparadigm
• Gradual typing
• Metaprogramming
• Domain Specific Language support
 Command chains
• Cranes and tortoises revisited
• 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
• Equivalent to:
move forward at 3.km/h
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
Part 3: What makes Groovy Awesome?
• Java integration
• Scripting support
• Multiparadigm
• Gradual typing
• Metaprogramming
• Domain Specific Language support
• Command chains
 Cranes and tortoises revisited
• Ecosystem
• Community/Team
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
@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 "$numCranesn$numTortoises"
else
println "No Solutions" Cranes = 4
Tortoises = 3
ChocoCraneTortoise.groovy
Logic programming example
dslUntyped/ChocoCraneTortoiseDSL.groovy
50 lines to define the DSL
Logic programming example
cranes have 2 legs
tortoises have 4 legs
there are 7 animals
there are 20 legs
display solution
Cranes 4
Tortoises 3
dslUntyped/ChocoCraneTortoiseDSL.groovy
50 lines to define the DSL
Logic programming example
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
dslUntyped/ChocoCraneTortoiseDSL.groovy
50 lines to define the DSL
Logic programming example
Crane(2), Tortoise(4), Beetle(6), Centipede(100), Millipede(1000)
Solution: Tortoise = 3, Beetle = 23
Solution: Crane = 1, Tortoise = 1, Beetle = 24
Solution: Crane = 25, Centipede = 1
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
}
@TypeChecked
def main() {
animals seen include Crane, Tortoise, Beetle, Centipede
leg count is 150
head count is 26
display solution
}
Logic programming example
dslTyped/ChocoCraneTortoiseDSL.groovy
80 lines to define the DSL
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
@TypeChecked(extensions='NatureServeAnimalProvider.groovy')
def main() {
animals seen include SandhillCrane, GopherTortoise, ChihuahuanMillipede
leg count is 1020
head count is 8
display solution
}
Custom checker
provider/ChocoCraneTortoiseProvider.groovy
80 lines to define the DSL
25 lines to define the provider
Awesome
Awesome
Awesome
Awesome
Ecosystem
Groovy's Awesome Team
Groovy's Awesome Team
Groovy's Awesome Team
+100's of others
Direct downloads:
2013: approx. 3 million
2014: 4+ million
2015: 12+ million
now: 2+ million/month
Groovy's Awesome Team
+100's of others just like YOU!
http://www.manning.com/koenig2
Groovy in Action 2nd edition
Manning promo code:
ctwg3sum
(39% off all Manning books)
152

Weitere ähnliche Inhalte

Was ist angesagt?

Clean Code I - Best Practices
Clean Code I - Best PracticesClean Code I - Best Practices
Clean Code I - Best Practices
Theo Jungeblut
 

Was ist angesagt? (20)

Dotnet Basics Presentation
Dotnet Basics PresentationDotnet Basics Presentation
Dotnet Basics Presentation
 
C# 101: Intro to Programming with C#
C# 101: Intro to Programming with C#C# 101: Intro to Programming with C#
C# 101: Intro to Programming with C#
 
.NET and C# Introduction
.NET and C# Introduction.NET and C# Introduction
.NET and C# Introduction
 
Clean Code I - Best Practices
Clean Code I - Best PracticesClean Code I - Best Practices
Clean Code I - Best Practices
 
Deeper Dive in Docker Overlay Networks
Deeper Dive in Docker Overlay NetworksDeeper Dive in Docker Overlay Networks
Deeper Dive in Docker Overlay Networks
 
Course 102: Lecture 26: FileSystems in Linux (Part 1)
Course 102: Lecture 26: FileSystems in Linux (Part 1) Course 102: Lecture 26: FileSystems in Linux (Part 1)
Course 102: Lecture 26: FileSystems in Linux (Part 1)
 
Bridge pattern for Dummies
Bridge pattern for DummiesBridge pattern for Dummies
Bridge pattern for Dummies
 
Intro to Terraform
Intro to TerraformIntro to Terraform
Intro to Terraform
 
SOLID Principles and Design Patterns
SOLID Principles and Design PatternsSOLID Principles and Design Patterns
SOLID Principles and Design Patterns
 
Complete Guide for Linux shell programming
Complete Guide for Linux shell programmingComplete Guide for Linux shell programming
Complete Guide for Linux shell programming
 
Introduction to Scala
Introduction to ScalaIntroduction to Scala
Introduction to Scala
 
Command Design Pattern
Command Design PatternCommand Design Pattern
Command Design Pattern
 
Course 102: Lecture 8: Composite Commands
Course 102: Lecture 8: Composite Commands Course 102: Lecture 8: Composite Commands
Course 102: Lecture 8: Composite Commands
 
Iterator
IteratorIterator
Iterator
 
Chain of responsibility
Chain of responsibilityChain of responsibility
Chain of responsibility
 
AWS VPC by hellocloud.io
AWS VPC by hellocloud.ioAWS VPC by hellocloud.io
AWS VPC by hellocloud.io
 
Flutter
FlutterFlutter
Flutter
 
Helm Charts Security 101
Helm Charts Security 101Helm Charts Security 101
Helm Charts Security 101
 
flutter.school #HelloWorld
flutter.school #HelloWorldflutter.school #HelloWorld
flutter.school #HelloWorld
 
Linux Basic Commands
Linux Basic CommandsLinux Basic Commands
Linux Basic Commands
 

Andere mochten auch

Gr8conf - The Groovy Ecosystem Revisited
Gr8conf - The Groovy Ecosystem RevisitedGr8conf - The Groovy Ecosystem Revisited
Gr8conf - The Groovy Ecosystem Revisited
Andres Almiray
 
concurrency gpars
concurrency gparsconcurrency gpars
concurrency gpars
Paul King
 

Andere mochten auch (20)

Gr8conf - The Groovy Ecosystem Revisited
Gr8conf - The Groovy Ecosystem RevisitedGr8conf - The Groovy Ecosystem Revisited
Gr8conf - The Groovy Ecosystem Revisited
 
groovy transforms
groovy transformsgroovy transforms
groovy transforms
 
groovy databases
groovy databasesgroovy databases
groovy databases
 
Going to Mars with Groovy Domain-Specific Languages
Going to Mars with Groovy Domain-Specific LanguagesGoing to Mars with Groovy Domain-Specific Languages
Going to Mars with Groovy Domain-Specific Languages
 
Greach - The Groovy Ecosystem
Greach - The Groovy EcosystemGreach - The Groovy Ecosystem
Greach - The Groovy Ecosystem
 
Making the Most of Your Gradle Build
Making the Most of Your Gradle BuildMaking the Most of Your Gradle Build
Making the Most of Your Gradle Build
 
Make Your Testing Groovy
Make Your Testing GroovyMake Your Testing Groovy
Make Your Testing Groovy
 
concurrency gpars
concurrency gparsconcurrency gpars
concurrency gpars
 
Practical Tips for Oracle Business Intelligence Applications 11g Implementations
Practical Tips for Oracle Business Intelligence Applications 11g ImplementationsPractical Tips for Oracle Business Intelligence Applications 11g Implementations
Practical Tips for Oracle Business Intelligence Applications 11g Implementations
 
GoldenGate and ODI - A Perfect Match for Real-Time Data Warehousing
GoldenGate and ODI - A Perfect Match for Real-Time Data WarehousingGoldenGate and ODI - A Perfect Match for Real-Time Data Warehousing
GoldenGate and ODI - A Perfect Match for Real-Time Data Warehousing
 
A Walk Through the Kimball ETL Subsystems with Oracle Data Integration - Coll...
A Walk Through the Kimball ETL Subsystems with Oracle Data Integration - Coll...A Walk Through the Kimball ETL Subsystems with Oracle Data Integration - Coll...
A Walk Through the Kimball ETL Subsystems with Oracle Data Integration - Coll...
 
A Walk Through the Kimball ETL Subsystems with Oracle Data Integration
A Walk Through the Kimball ETL Subsystems with Oracle Data IntegrationA Walk Through the Kimball ETL Subsystems with Oracle Data Integration
A Walk Through the Kimball ETL Subsystems with Oracle Data Integration
 
Oracle GoldenGate and Apache Kafka A Deep Dive Into Real-Time Data Streaming
Oracle GoldenGate and Apache Kafka A Deep Dive Into Real-Time Data StreamingOracle GoldenGate and Apache Kafka A Deep Dive Into Real-Time Data Streaming
Oracle GoldenGate and Apache Kafka A Deep Dive Into Real-Time Data Streaming
 
그루비 소개 발표자료 - 김연수
그루비 소개 발표자료 - 김연수그루비 소개 발표자료 - 김연수
그루비 소개 발표자료 - 김연수
 
GoldenGate and Oracle Data Integrator - A Perfect Match- Upgrade to 12c
GoldenGate and Oracle Data Integrator - A Perfect Match- Upgrade to 12cGoldenGate and Oracle Data Integrator - A Perfect Match- Upgrade to 12c
GoldenGate and Oracle Data Integrator - A Perfect Match- Upgrade to 12c
 
Real-time Data Warehouse Upgrade – Success Stories
Real-time Data Warehouse Upgrade – Success StoriesReal-time Data Warehouse Upgrade – Success Stories
Real-time Data Warehouse Upgrade – Success Stories
 
GoldenGate and Oracle Data Integrator - A Perfect Match...
GoldenGate and Oracle Data Integrator - A Perfect Match...GoldenGate and Oracle Data Integrator - A Perfect Match...
GoldenGate and Oracle Data Integrator - A Perfect Match...
 
Real-Time Data Replication to Hadoop using GoldenGate 12c Adaptors
Real-Time Data Replication to Hadoop using GoldenGate 12c AdaptorsReal-Time Data Replication to Hadoop using GoldenGate 12c Adaptors
Real-Time Data Replication to Hadoop using GoldenGate 12c Adaptors
 
Vert.X like Node.js but polyglot and reactive on JVM
Vert.X like Node.js but polyglot and reactive on JVMVert.X like Node.js but polyglot and reactive on JVM
Vert.X like Node.js but polyglot and reactive on JVM
 
Java Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to Miss Java Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to Miss
 

Ähnlich wie awesome groovy

groovy rules
groovy rulesgroovy rules
groovy rules
Paul King
 
Polyglot Programming in the JVM
Polyglot Programming in the JVMPolyglot Programming in the JVM
Polyglot Programming in the JVM
Andres Almiray
 
Polyglot Programming @ Jax.de 2010
Polyglot Programming @ Jax.de 2010Polyglot Programming @ Jax.de 2010
Polyglot Programming @ Jax.de 2010
Andres Almiray
 

Ähnlich wie awesome groovy (20)

groovy rules
groovy rulesgroovy rules
groovy rules
 
Groovy
GroovyGroovy
Groovy
 
Einführung in TypeScript
Einführung in TypeScriptEinführung in TypeScript
Einführung in TypeScript
 
2007 09 10 Fzi Training Groovy Grails V Ws
2007 09 10 Fzi Training Groovy Grails V Ws2007 09 10 Fzi Training Groovy Grails V Ws
2007 09 10 Fzi Training Groovy Grails V Ws
 
Building a friendly .NET SDK to connect to Space
Building a friendly .NET SDK to connect to SpaceBuilding a friendly .NET SDK to connect to Space
Building a friendly .NET SDK to connect to Space
 
concurrency with GPars
concurrency with GParsconcurrency with GPars
concurrency with GPars
 
Introduction to Oracle Groovy
Introduction to Oracle GroovyIntroduction to Oracle Groovy
Introduction to Oracle Groovy
 
Polyglot Programming in the JVM
Polyglot Programming in the JVMPolyglot Programming in the JVM
Polyglot Programming in the JVM
 
The Great Scala Makeover
The Great Scala MakeoverThe Great Scala Makeover
The Great Scala Makeover
 
TDD with PhpSpec
TDD with PhpSpecTDD with PhpSpec
TDD with PhpSpec
 
Groovy On Trading Desk (2010)
Groovy On Trading Desk (2010)Groovy On Trading Desk (2010)
Groovy On Trading Desk (2010)
 
Top 20 java programming interview questions for sdet
Top 20 java programming interview questions for sdetTop 20 java programming interview questions for sdet
Top 20 java programming interview questions for sdet
 
Writing Groovy DSLs
Writing Groovy DSLsWriting Groovy DSLs
Writing Groovy DSLs
 
Polyglot Programming @ Jax.de 2010
Polyglot Programming @ Jax.de 2010Polyglot Programming @ Jax.de 2010
Polyglot Programming @ Jax.de 2010
 
Introduction To Scala
Introduction To ScalaIntroduction To Scala
Introduction To Scala
 
The Curious Clojurist - Neal Ford (Thoughtworks)
The Curious Clojurist - Neal Ford (Thoughtworks)The Curious Clojurist - Neal Ford (Thoughtworks)
The Curious Clojurist - Neal Ford (Thoughtworks)
 
Introduction To Groovy 2005
Introduction To Groovy 2005Introduction To Groovy 2005
Introduction To Groovy 2005
 
Groovy for Java Developers
Groovy for Java DevelopersGroovy for Java Developers
Groovy for Java Developers
 
Groovy
GroovyGroovy
Groovy
 
Apache Groovy: the language and the ecosystem
Apache Groovy: the language and the ecosystemApache Groovy: the language and the ecosystem
Apache Groovy: the language and the ecosystem
 

Mehr von Paul King

functional groovy
functional groovyfunctional groovy
functional groovy
Paul King
 
Craig Smith & Paul King Agile Tool Hacking Taking Your Agile Development ...
Craig Smith & Paul King   Agile Tool Hacking   Taking Your Agile Development ...Craig Smith & Paul King   Agile Tool Hacking   Taking Your Agile Development ...
Craig Smith & Paul King Agile Tool Hacking Taking Your Agile Development ...
Paul King
 
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
Paul King
 

Mehr von Paul King (15)

tictactoe groovy
tictactoe groovytictactoe groovy
tictactoe groovy
 
functional groovy
functional groovyfunctional groovy
functional groovy
 
Make Testing Groovy
Make Testing GroovyMake Testing Groovy
Make Testing Groovy
 
Agile Testing Practices
Agile Testing PracticesAgile Testing Practices
Agile Testing Practices
 
groovy DSLs from beginner to expert
groovy DSLs from beginner to expertgroovy DSLs from beginner to expert
groovy DSLs from beginner to expert
 
groovy and concurrency
groovy and concurrencygroovy and concurrency
groovy and concurrency
 
GroovyDSLs
GroovyDSLsGroovyDSLs
GroovyDSLs
 
Atlassian Groovy Plugins
Atlassian Groovy PluginsAtlassian Groovy Plugins
Atlassian Groovy Plugins
 
Dynamic Language Practices
Dynamic Language PracticesDynamic Language Practices
Dynamic Language Practices
 
Make Your Builds More Groovy
Make Your Builds More GroovyMake Your Builds More Groovy
Make Your Builds More Groovy
 
Groovy Power Features
Groovy Power FeaturesGroovy Power Features
Groovy Power Features
 
Groovy Testing Sep2009
Groovy Testing Sep2009Groovy Testing Sep2009
Groovy Testing Sep2009
 
Craig Smith & Paul King Agile Tool Hacking Taking Your Agile Development ...
Craig Smith & Paul King   Agile Tool Hacking   Taking Your Agile Development ...Craig Smith & Paul King   Agile Tool Hacking   Taking Your Agile Development ...
Craig Smith & Paul King Agile Tool Hacking Taking Your Agile Development ...
 
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
 
XML and Web Services with Groovy
XML and Web Services with GroovyXML and Web Services with Groovy
XML and Web Services with Groovy
 

Kürzlich hochgeladen

TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
mohitmore19
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
masabamasaba
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Health
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
masabamasaba
 

Kürzlich hochgeladen (20)

TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
Generic or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisionsGeneric or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisions
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdfThe Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 

awesome groovy

  • 1. Dr Paul King Groovy Lead for Object Computing Inc. @paulk_asert http:/slideshare.net/paulk_asert/awesome-groovy https://github.com/paulk-asert/awesome-groovy Apache Groovy: The Awesome Parts FRIEND OF GROOVY
  • 2.
  • 4. What is Groovy? 4 Groovy = Java – boiler plate code + closures (1st class FP) + extensible type system + runtime & compile-time metaprogramming + flexible language grammar (DSLs) + scripting + GDK library “Groovy is like a super version of Java. It leverages Java features but adds productivity features and provides great flexibility and extensibility.”
  • 5.
  • 7. Why Groovy? Too verbose Support functional programming Better concurrency Evolves too slowly I need feature XXX Too complex for some situations More flexibility Java
  • 8. Why Groovy? Groovy Make it simplerMake it dynamic Support simple scripting
  • 9. Why Groovy? Groovy Make it simplerMake it dynamic Support simple scripting Java integration
  • 10. Why Groovy? Groovy Make it simplerMake it dynamic Support simple scripting Good IDE support Java integration
  • 11. Why Groovy? Groovy Make it simplerMake it dynamic Support simple scripting Good IDE support Custom features Java integration
  • 12. Why Groovy? Groovy Make it simplerMake it dynamic Support simple scripting Support concurrency Good IDE support Custom features Java integration
  • 13. Why Groovy? Groovy Make it simplerMake it dynamic Support simple scripting Support functional style Support concurrency Good IDE support Custom features Java integration
  • 14.
  • 15. 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); } } return result; } public static void main(String[] args) { 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); } } }
  • 16. 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); if (s.length() < length) { result.add(s); } } return result; } public static void main(String[] args) { 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); } } } Rename Main.java to Main.groovy
  • 17. Some Java Boilerplate identified 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); } } return result; } public static void main(String[] args) { 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); } } } Are the semicolons needed? And shouldn’t we us more modern list notation? Why not import common libraries? Do we need the static types? Must we always have a main method and class definition? How about improved consistency?
  • 18. Java Boilerplate removed def keepShorterThan(strings, length) { def result = new ArrayList() for (s in strings) { if (s.size() < length) { result.add(s) } } return result } names = new ArrayList() 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) }
  • 19. More Java Boilerplate identified def keepShorterThan(strings, length) { def result = new ArrayList() for (s in strings) { if (s.size() < length) { result.add(s) } } return result } names = new ArrayList() 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) } Shouldn’t we have special notation for lists? And special facilities for list processing? Is ‘return’ needed at end? Is the method now needed? Simplify common methods? Remove unambiguous brackets?
  • 20. 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 } ["Ted", "Fred", "Jed", "Ned"] 3 Ted Jed Ned Output:
  • 21. 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 // plus a DSL implementation
  • 22. 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 names = [] def of, having, less def given(_the) { [names:{ Object[] ns -> names.addAll(ns) [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 }
  • 23. Or Groovy DSL version if required • Or use GDSL (IntelliJ IDEA) or DSLD (Eclipse) 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
  • 24. 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 … enum The { the } enum Having { having } enum Of { of } … class DisplayThe { DisplayTheNamesHaving names(Having having) { new DisplayTheNamesHaving() } DisplayTheNumberOf number(Of of) { new DisplayTheNumberOf() } } … // plus 50 lines
  • 25. Or typed Groovy DSL version if required
  • 26. Groovy DSL being debugged
  • 27. 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 }
  • 28. 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 } afterMethodCall { mc -> mc.arguments.each { if (isConstantExpression(it)) { if (it.value instanceof String && !it.value.endsWith('ed')) { addStaticTypeError("I don't like the name '${it.value}'", mc) } } } } 
  • 29. @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 } Or typed Groovy DSL version if required afterMethodCall { mc -> mc.arguments.each { if (isConstantExpression(it)) { if (it.value instanceof String && !it.value.endsWith('ed')) { addStaticTypeError("I don't like the name '${it.value}'", mc) } } } }
  • 30. @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 } afterMethodCall { mc -> mc.arguments.each { if (isConstantExpression(it)) { 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
  • 31. @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 } afterMethodCall { mc -> mc.arguments.each { if (isConstantExpression(it)) { 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 
  • 32. What style of language is Groovy?
  • 33. Groovy Style • Imperative/OO but somewhat paradigm agnostic •Dynamic, optionally static (gradual extensible typing) • Extensible language features through metaprogramming
  • 34. Part 2: What makes Groovy Awesome?
  • 35. What makes Groovy Awesome? • Java integration • Scripting support • Multiparadigm • Gradual typing • Metaprogramming • Domain specific language (DSL) support • Ecosystem • Community/Team Awesome
  • 36. 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
  • 37. Java Integration • Groovy is Java’s friend Java Groovy
  • 38. Java Integration • Standing on the shoulders of Giants • Some limitations inherited but much gained through new releases of Java • Rock solid foundation • Can ease migration to new versions of Java Java Groovy
  • 39. Java Integration • Seamless integration • IDEs provide cross-language compile, navigation, and refactoring • Arbitrarily mix source language • Drop-in replace any class • Overloaded methods • Syntax alignment • Shared data types Java Groovy
  • 40. Java Integration • Seamless integration • IDEs provide cross-language compile, navigation, and refactoring • Arbitrarily mix source language • Drop-in replace any class • Overloaded methods • Syntax alignment • Shared data types Java Groovy
  • 41. Java Integration • Polyglot friendly • Typically integrates well with other languages which integrate with Java • JRuby • Jython • Scala • Frege • Clojure • R through Renjin • JavaScript (Rhino/Nashorn)
  • 42. Java Integration • Polyglot friendly • JSR-223 scripting to talk to JavaScript 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 GroovyJavaScript
  • 43. 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) { y <- 1 for (i in 1:x) { y <- y * i } return(y) } ''' assert eval('factorial(4)')[0] == 24 } Java GroovyR
  • 44. Grooscript @Grab('org.grooscript:grooscript:1.2.0') import org.grooscript.GrooScript import javax.script.ScriptEngineManager def groojs = GrooScript.convert ''' def sayHello = { println "Hello ${it}!" } ['Groovy','JavaScript','GrooScript'].each sayHello''', [initialText: 'var console = { log: print }', addGsLib: 'grooscript.min'] new ScriptEngineManager().getEngineByName("nashorn").eval(groojs) Hello Groovy! Hello JavaScript! Hello GrooScript! Jorge Franco, grooscript.org Convert Groovy subset to JavaScript Support: Gradle, Grails, NPM Demos: react.js, node.js, Pollock Converts: Classes, closures, Date primitives, ranges, String/GString Special: builder, templates, gQuery
  • 45. 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 Awesome • Friend of Java • Integration • Good JVM Citizen
  • 46. 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 Awesome
  • 47. Scripting • Terse format • Isolation • Domain-Specific Languages (DSLs) • Security • Flexibility
  • 48. Scripting • Leave out surrounding class • Entire source file: public class Script { public static void main(String[] args) { System.out.println("Hello world"); } } println "Hello world"
  • 49. 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
  • 53. Scripting class Robot { void move(dir) { println "robot moved $dir" } } def robot = new Robot()
  • 54. 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
  • 55. Scripting move left 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
  • 56. Scripting move left def robot = new Robot() def binding = new Binding(/* ... */) def imports = new ImportCustomizer().addStaticStars('java.lang.Math') def timeout = new ASTTransformationCustomizer(value: 2, TimedInterrupt) def secure = new SecureASTCustomizer().with { closuresAllowed = false importsWhitelist = [] tokensWhitelist = [ PLUS, MINUS, MULTIPLY, DIVIDE, /*...*/ ] //... } def sysExit = new CompilationCustomizer(CANONICALIZATION) { void call(SourceUnit src, GeneratorContext ctxt, ClassNode cn) { new ClassCodeVisitorSupport() { void visitMethodCallExpression(MethodCallExpression call) { // check for System.exit() } // ... }.visitClass(cn) } } def config = new CompilerConfiguration() config.addCompilationCustomizers(imports, timeout, secure, sysExit) def shell = new GroovyShell(binding, config)
  • 57. Scripting move left move forward at 3.km/h More examples later
  • 58. 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 Awesome • Simpler scripting • Separation of concerns
  • 59. What makes Groovy Awesome? • Java integration • Scripting support • Multiparadigm • Object-oriented • Functional, Closures • Logic/Dataflow programming • Gradual typing • Metaprogramming • Domain Specific Language support • Ecosystem • Community/Team
  • 60. Multiparadigm • Imperative roots from Java • OO abstractions: classes, interfaces, inheritance • Properties • Traits • First class functional support via closures • External libraries for advanced features • Other paradigms via libraries • Logic, dataflow, reactive Awesome
  • 62. Rich 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
  • 63. 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!"
  • 64. Rich functional features • Closures • First-class functions • Higher-order functions • Map, reduce, filter • Mutable & immutable data • Recursion • Lazy & eager evaluation • Advanced FP techniques • Memoization, Trampolines, Composition, Curry • Concurrency
  • 65. 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'
  • 66. map/filter/reduce (+ functional style) @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' def young = { person, threshold -> person.age < threshold }.rcurry(40).memoize() assert people .findAll(young) .collect{ it.name.toUpperCase() } .sort() .join(', ') == 'MARY, PAUL'
  • 67. map/filter/reduce (+ with streams) @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' // requires JRE 8 def commaSep = Collectors.joining(", ") assert people.stream() .filter{ it.age < 40 } .map{ it.name.toUpperCase() } .sorted() .collect(commaSep) == 'MARY, PAUL'
  • 68. Logic/Constraint programming • Logic programming • Declarative style • Logic clauses for example Prolog • 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
  • 69. Logic programming example cranes have 2 legs tortoises have 4 legs there are 7 animals there are 20 legs How many of each animal?
  • 70. Constraint programming example @Grab('org.choco-solver:choco-solver:4.0.4') 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 "$numCranesn$numTortoises" else println "No Solutions" Cranes = 4 Tortoises = 3 ChocoCraneTortoise.groovy See also: JSR-331 Constraint Programming API
  • 71. Dataflow programming • 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
  • 72. 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 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 72 Awesome
  • 73. Concurrency challenge • We can analyse the example’s task graph: def (f1, f2, f3, f4) = [{ sleep 1000; it }] * 3 + [{ x, y -> x + y }] def a = 5 def b = f1(a) def c = f2(a) def d = f3(c) def f = f4(b, d) assert f == 10
  • 74. Concurrency challenge • We can analyse the example’s task graph: def (f1, f2, f3, f4) = [{ sleep 1000; it }] * 3 + [{ x, y -> x + y }] def a = 5 def b = f1(a) def c = f2(a) def d = f3(c) def f = f4(b, d) assert f == 10 f2 f3 f1 f4 aa b c d f
  • 75. Concurrency challenge • Manually using asynchronous functions: def (f1, f2, f3, f4) = [{ sleep 1000; it }] * 3 + [{ x, y -> x + y }] import static groovyx.gpars.GParsPool.withPool withPool(2) { def a = 5 def futureB = f1.callAsync(a) def c = f2(a) def d = f3(c) def f = f4(futureB.get(), d) assert f == 10 } f2 f3 f1 f4 aa futureB c d f
  • 76. 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 new Dataflows().with { task { a = 5 } task { b = f1(a) } task { c = f2(a) } task { d = f3(c) } task { f = f4(b, d) } assert f == 10 } f2 f3 f1 f4 aa b c d f
  • 77. 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 new Dataflows().with { task { f = f4(b, d) } task { d = f3(c) } task { c = f2(a) } task { b = f1(a) } task { a = 5 } assert f == 10 } f2 f3 f1 f4 aa b c d f
  • 78. What makes Groovy Awesome? • Java integration • Scripting support • Multiparadigm • Object-oriented • Functional, Closures • Logic/dataflow programming • Gradual typing • Metaprogramming • Domain Specific Language support • Ecosystem • Community/Team • Ability to use imperative when needed for speed • Numerous declarative approaches available when it makes sense Awesome
  • 79. What makes Groovy Awesome? • Java integration • Scripting support • Multiparadigm • Gradual typing • Dynamic strong typing • Static type checking • Extensible • Type inference • Metaprogramming • Domain Specific Language support • Ecosystem • Community/Team
  • 80. Gradual typing • Dynamic by default • Gradual typing • Static type checking • Extensible type system Awesome
  • 81. Dynamic vs static 82 def myPets = ['Lassie', 'Skip'] List<String> yourPets = ['Lassie', 'Skip'] shouldFail(ClassCastException) { List ourPets = new Date() }
  • 82. Dynamic vs static 83 Gradual Type-time? def myPets = ['Lassie', 'Skip'] List<String> yourPets = ['Lassie', 'Skip'] shouldFail(ClassCastException) { List ourPets = new Date() }
  • 83. Dynamic vs static 84 def myPets = ['Lassie', 'Skip'] List<String> yourPets = ['Lassie', 'Skip'] shouldFail(ClassCastException) { List ourPets = new Date() } def adder = { a, b -> a + b } assert adder(100, 200) == 300 assert adder('X', 'Y') == 'XY'
  • 84. Dynamic vs static 85 def adder = { a, b -> a + b } assert adder(100, 200) == 300 assert adder('X', 'Y') == 'XY' def myPets = ['Lassie', 'Skip'] List<String> yourPets = ['Lassie', 'Skip'] shouldFail(ClassCastException) { List ourPets = new Date() } Duck-typing
  • 85. Dynamic vs static 86 def adder = { a, b -> a + b } assert adder(100, 200) == 300 assert adder('X', 'Y') == 'XY' def myPets = ['Lassie', 'Skip'] List<String> yourPets = ['Lassie', 'Skip'] shouldFail(ClassCastException) { List ourPets = new Date() } @TypeChecked def myMethod() { def myPets = ['Lassie', 'Skip'] List yourPets = ['Lassie', 'Skip'] } shouldFail(CompilationFailedException) { assertScript ''' @groovy.transform.TypeChecked def yourMethod() { List ourPets = new Date() } ''' }
  • 86. Dynamic vs static 87 def adder = { a, b -> a + b } assert adder(100, 200) == 300 assert adder('X', 'Y') == 'XY' def myPets = ['Lassie', 'Skip'] List<String> yourPets = ['Lassie', 'Skip'] shouldFail(ClassCastException) { List ourPets = new Date() } @TypeChecked def myMethod() { def myPets = ['Lassie', 'Skip'] List yourPets = ['Lassie', 'Skip'] } shouldFail(CompilationFailedException) { assertScript ''' @groovy.transform.TypeChecked def yourMethod() { List ourPets = new Date() } ''' } Extensible Inference
  • 87. Extensible type checking 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' 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.
  • 88. Extensible type checking import groovy.sql.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
  • 89. Static compilation import groovy.transform.* class Actor { String firstName, lastName @CompileStatic String getFullName() { "$firstName $lastName" } void makePeace() { new AntBuilder().echo('Peace was never an option') } } def magneto = new Actor(firstName: 'Ian', lastName: 'McKellen') assert magneto.fullName == 'Ian McKellen' magneto.makePeace()
  • 91. What makes Groovy Awesome? • Java integration • Scripting support • Multiparadigm • Gradual typing • Dynamic strong typing • Static type checking • Extensible • Type inference • Metaprogramming • Domain Specific Language support • Ecosystem • Community/Team • Maximise duck-typing • Minimise noise • yet type inference • Flexibility at runtime • As strict as you want when needed • Fast when needed Awesome
  • 92. What makes Groovy Awesome? • Java integration • Scripting support • Multiparadigm • Gradual typing • Metaprogramming • Runtime • Compile-time • Macros • Domain Specific Language support • Ecosystem • Community/Team
  • 93. Runtime metaprogramming • 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 Awesome* * Individual levels of awesomeness may vary
  • 94. Runtime metaprogramming • Adding methods at runtime assert 'Hello'.reverse() == 'olleH' String.metaClass.swapCase = { delegate.collect{ it in 'A'..'Z' ? it.toLowerCase() : it.toUpperCase() }.join() } assert 'Hello'.swapCase() == 'hELLO'
  • 95. Runtime metaprogramming • Intercepting methods class Foo { def one() { println "Called one()" } def methodMissing(String name, params) { println "Attempted $name($params)" } } def f = new Foo() f.one() f.two() f.three('Some Arg') Called one() Attempted two([]) Attempted three([Some Arg])
  • 96. XML Parsing/GPath expressions def xml = ''' <hosts> <host name='MyHost'> <service name='MyMicroService'/> <service name='MyNanoService'/> </host> </hosts> ''' def hosts = new XmlParser().parseText(xml) assert hosts.host.service[0].@name=='MyMicroService'
  • 97. def xml = ''' <hosts> <host name='MyHost'> <service name='MyMicroService'/> <service name='MyNanoService'/> </host> </hosts> ''' def hosts = new XmlParser().parseText(xml) assert hosts.host.service[0].@name=='MyMicroService' XML Parsing/GPath expressions
  • 98. Compile-time metaprogramming • Gives you the ability to change the language by augmenting the compilation process Awesome
  • 99. 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)
  • 100. 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)
  • 101. Parsing Summary public run() ... L1 ALOAD 1 LDC 1 AALOAD ALOAD 0 LDC "Howdy Y'all" INVOKEINTERFACE callCurrent() ARETURN ... println "Howdy Y'all" BlockStatement -> ReturnStatement -> MethodCallExpression -> VariableExpression("this") -> ConstantExpression("println") -> ArgumentListExpression -> ConstantExpression("Howdy Y'all") MyScript.groovy > groovy MyScript.groovy > groovyc MyScript.groovy > groovysh > groovyConsole
  • 102. • 9 phase compiler – Early stages: read source code and convert into a sparse syntax tree – Middle stages: iteratively build up a more dense and information rich version of the syntax tree – Later stages: check the tree and convert it into byte code/class files Initialization Semantic Analysis Instruction Selection Parsing Conversion Canonicalization Class Generation Output Finalization Parsing Summary
  • 103. Parsing - Early Stages Initialization Semantic Analysis Instruction Selection Parsing Conversion Canonicalization Class Generation Output Finalization @ToString class Greeter { String message = "Howdy Y'all" void greet() { println message } } ClassNode: Greeter MethodNode: greet Property: message type: unresolved(String) AnnotationNode: ToString type: unresolved(ToString) methods: properties: annotations: BlockStatement MethodCall: this.println(message)
  • 104. Parsing - Middle Stages Initialization Semantic Analysis Instruction Selection Parsing Conversion Canonicalization Class Generation Output Finalization ClassNode: Greeter MethodNode: greet FieldNode: message type: resolved(String) methods: fields: constructors: ConstructorNode MethodNode: getMessageMethodNode: setMessageMethodNode: toString MethodNode: getMetaClass…
  • 105. Parsing - Final Stages 106 Initialization Semantic Analysis Instruction Selection Parsing Conversion Canonicalization Class Generation Output Finalization public greet()V ... L1 ... ALOAD 0 GETFIELD Greeter.message INVOKEINTERFACE callCurrent() POP ...
  • 106. Immutable Classes • Some Rules • Don’t provide mutators • Ensure that no methods can be overridden o Easiest to make the class final o Or use static factories & non-public constructors • Make all fields final • Make all fields private o Avoid even public immutable constants • Ensure exclusive access to any mutable components o Don’t leak internal references o Defensive copying in and out • Optionally provide equals and hashCode methods • Optionally provide toString method
  • 107. @Immutable... • Java Immutable Class • As per Joshua Bloch Effective Java public final class Person { private final String first; private final String last; public String getFirst() { return first; } public String getLast() { return last; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((first == null) ? 0 : first.hashCode()); result = prime * result + ((last == null) ? 0 : last.hashCode()); return result; } public Person(String first, String last) { this.first = first; this.last = last; } // ... // ... @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Person other = (Person) obj; if (first == null) { if (other.first != null) return false; } else if (!first.equals(other.first)) return false; if (last == null) { if (other.last != null) return false; } else if (!last.equals(other.last)) return false; return true; } @Override public String toString() { return "Person(first:" + first + ", last:" + last + ")"; } }
  • 108. ...@Immutable... public final class Person { private final String first; private final String last; public String getFirst() { return first; } public String getLast() { return last; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((first == null) ? 0 : first.hashCode()); result = prime * result + ((last == null) ? 0 : last.hashCode()); return result; } public Person(String first, String last) { this.first = first; this.last = last; } // ... // ... @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Person other = (Person) obj; if (first == null) { if (other.first != null) return false; } else if (!first.equals(other.first)) return false; if (last == null) { if (other.last != null) return false; } else if (!last.equals(other.last)) return false; return true; } @Override public String toString() { return "Person(first:" + first + ", last:" + last + ")"; } } boilerplate• Java Immutable Class • As per Joshua Bloch Effective Java
  • 109. ...@Immutable @Immutable class Person { String first, last } Awesome
  • 110. With Macros (Groovy 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 { return new Date() }
  • 111. With Macros (Groovy 2.5+) Awesome 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 { return new Date() }
  • 112. With Macros (Groovy 2.5+) • Variations: • Expressions, Statements, Classes • Supports variable substitution, specifying compilation phase def ast = macro { return new Date() }
  • 113. With Macros (Groovy 2.5+) • AST Matching: • Selective transformations, filtering, testing • Supports placeholders Expression transform(Expression exp) { Expression ref = macro { 1 + 1 } if (ASTMatcher.matches(ref, exp)) { return macro { 2 } } return super.transform(exp) }
  • 114. Macro method examples class X { String name } class Y { List<X> list } class Z { Y y } Adapted from https://github.com/touchez-du-bois/akatsuki but adapted for the experimental Antlr4 “Parrot” parser. def getName(Z z) { z.y.list[0].name } • nullSafe
  • 115. Macro method examples class X { String name } class Y { List<X> list } class Z { Y y } def getName(Z z) { z.y.list[0].name } Adapted from https://github.com/touchez-du-bois/akatsuki but adapted for the experimental Antlr4 “Parrot” parser. • nullSafe
  • 116. Macro method examples class X { String name } class Y { List<X> list } class Z { Y y } def getName(Z z) { z.y.list[0].name } Prone to NPE Adapted from https://github.com/touchez-du-bois/akatsuki but adapted for the experimental Antlr4 “Parrot” parser. • nullSafe
  • 117. Macro method examples • nullSafe class X { String name } class Y { List<X> list } class Z { Y y } def getName(Z z) { def result = null if (z != null && z.y != null && z.y.list != null && z.y.list[0] != null) { result = z.y.list[0].name } result } Adapted from https://github.com/touchez-du-bois/akatsuki but adapted for the experimental Antlr4 “Parrot” parser.
  • 118. Macro method examples class X { String name } class Y { List<X> list } class Z { Y y } def getName(Z z) { def result = null if (z != null && z.y != null && z.y.list != null && z.y.list[0] != null) { result = z.y.list[0].name } result } Verbose Adapted from https://github.com/touchez-du-bois/akatsuki but adapted for the experimental Antlr4 “Parrot” parser. • nullSafe
  • 119. Macro method examples def getName(Z z) { z?.y?.list?[0]?.name } class X { String name } class Y { List<X> list } class Z { Y y } Adapted from https://github.com/touchez-du-bois/akatsuki but adapted for the experimental Antlr4 “Parrot” parser. • nullSafe
  • 120. class X { String name } class Y { List<X> list } class Z { Y y } Macro method examples Adapted from https://github.com/touchez-du-bois/akatsuki but adapted for the experimental Antlr4 “Parrot” parser. • nullSafe def getName(Z z) { nullSafe(z.y.list[0].name) }
  • 121. Macro method examples @Macro static Expression nullSafe(MacroContext macroContext, Expression expression) { if (expression instanceof PropertyExpression) { // exp.prop -> exp?.prop … } else if (expression instanceof MethodCallExpression) { // exp.method() -> exp?.method() … } return expression } • nullSafe def getName(Z z) { nullSafe(z.y.list[0].name) }
  • 122. Macro method examples 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 See: https://github.com/touchez-du-bois/akatsuki
  • 123. Macro method examples • 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) { expect: Math.max(a, b) == c where: a | b | c 1 | 3 | 3 7 | 4 | 7 0 | 0 | 0 } }
  • 124. Macro method examples 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 }
  • 125. What makes Groovy Awesome? • Java integration • Scripting support • Multiparadigm • Gradual typing • Metaprogramming • Runtime • Compile-time • Macros • Domain Specific Language support • Ecosystem • Community/Team • Ability to change the language at runtime • Ability to change the language during the compilation process • Macros provide a homogeneous form for writing AST transformations Awesome
  • 126. Part 2: What makes Groovy Awesome? • Java integration • Scripting support • Multiparadigm • Gradual typing • Metaprogramming • Domain Specific Language support  Command chains • Cranes and tortoises revisited • Ecosystem • Community/Team
  • 127. Command Chains • Ability to chain method calls without parentheses and dots Awesome
  • 128. Command Chains • Ability to chain method calls without parentheses and dots move forward at 3.km/h
  • 129. Command Chains • Ability to chain method calls without parentheses and dots • Equivalent to: move forward at 3.km/h move(forward).at(3.getKm().div(h))
  • 130. 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
  • 131. 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
  • 132. 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
  • 133. 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 …
  • 134. 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
  • 135. Part 3: What makes Groovy Awesome? • Java integration • Scripting support • Multiparadigm • Gradual typing • Metaprogramming • Domain Specific Language support • Command chains  Cranes and tortoises revisited • Ecosystem • Community/Team
  • 136. Logic programming example cranes have 2 legs tortoises have 4 legs there are 7 animals there are 20 legs How many of each animal?
  • 137. Recall: Constraint programming example @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 "$numCranesn$numTortoises" else println "No Solutions" Cranes = 4 Tortoises = 3 ChocoCraneTortoise.groovy
  • 139. Logic programming example cranes have 2 legs tortoises have 4 legs there are 7 animals there are 20 legs display solution Cranes 4 Tortoises 3 dslUntyped/ChocoCraneTortoiseDSL.groovy 50 lines to define the DSL
  • 140. Logic programming example 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 dslUntyped/ChocoCraneTortoiseDSL.groovy 50 lines to define the DSL
  • 141. Logic programming example Crane(2), Tortoise(4), Beetle(6), Centipede(100), Millipede(1000) Solution: Tortoise = 3, Beetle = 23 Solution: Crane = 1, Tortoise = 1, Beetle = 24 Solution: Crane = 25, Centipede = 1 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 }
  • 142. @TypeChecked def main() { animals seen include Crane, Tortoise, Beetle, Centipede leg count is 150 head count is 26 display solution } Logic programming example dslTyped/ChocoCraneTortoiseDSL.groovy 80 lines to define the DSL
  • 143. 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)) } }
  • 144. DSL Type Provider @TypeChecked(extensions='NatureServeAnimalProvider.groovy') def main() { animals seen include SandhillCrane, GopherTortoise, ChihuahuanMillipede leg count is 1020 head count is 8 display solution } Custom checker provider/ChocoCraneTortoiseProvider.groovy 80 lines to define the DSL 25 lines to define the provider
  • 148. Groovy's Awesome Team +100's of others Direct downloads: 2013: approx. 3 million 2014: 4+ million 2015: 12+ million now: 2+ million/month
  • 149. Groovy's Awesome Team +100's of others just like YOU!
  • 150.
  • 151. http://www.manning.com/koenig2 Groovy in Action 2nd edition Manning promo code: ctwg3sum (39% off all Manning books) 152