SlideShare ist ein Scribd-Unternehmen logo
1 von 99
Downloaden Sie, um offline zu lesen
©ASERT2006-2013
Dr Paul King
@paulk_asert
http:/slideshare.net/paulk_asert/functional-groovy
https://github.com/paulk-asert/functional-groovy
Functional Groov
Topics
Intro to Functional Style
• Functional Basics
• Immutability & Persistent Data Structures
• Laziness & Strictness
• Gpars & Concurrency
• Type Safety
• Word Split (bonus material)
• More Info
©ASERT2006-2013
Introduction
• What is functional programming?
– Favour evaluation of composable
expressions over execution of commands
– Encourage particular idioms such as side-
effect free functions & immutability
• And why should I care?
– Declarative understandable code
– Reduction of errors
– Better patterns and approaches to design
– Improved reusability
– Leverage concurrency
©ASERT2006-2013
What makes up functional style?
• Functions, Closures, Lambdas, Blocks as
first-class citizens
• Higher order functions
• Mutable vs Immutable data structures
• Recursion
• Lazy vs Eager evaluation
• Declarative vs Imperative style
• Advanced Techniques
– Memoization, Trampolines, Composition and Curry
• Compile-time safety
• Concurrency
Closures...
©ASERT2006-2013
def twice = { int num -> num + num }
assert twice(5) == 10
assert twice.call(6) == 12
def twice10 = { 2 * 10 }
assert 20 == twice10()
def triple = { arg -> arg * 3 }
assert triple(5) == 15
def alsoTriple = { it * 3 }
assert alsoTriple(6) == 18
def quadruple = { arg = 2 -> twice(arg) * 2 }
assert quadruple(5) == 20
assert quadruple() == 8
// ...
...Closures...
©ASERT2006-2013
// ...
def callWith5(Closure c) {
c(5)
}
assert 15 == callWith5(triple)
def twiceMethod(int num) { num * 2 }
assert twiceMethod(2) == 4
def alsoTwice = this.&twiceMethod
assert alsoTwice(5) == 10
def alsoQuadruple = twice >> twice
assert alsoQuadruple(5) == 20
def forty = quadruple.curry(10)
assert forty() == 40
assert [10, 15, 20] == [twice, triple, quadruple].collect{ it(5) }
assert 45 == [alsoTwice, alsoTriple, alsoQuadruple].sum{ it(5) }
...Closures
• Used for many things in Groovy:
• Iterators
• Callbacks
• Higher-order functions
• Specialized control structures
• Dynamic method definition
• Resource allocation
• Threads
• Continuation-like coding
©ASERT2006-2013
def houston(Closure doit) {
(10..1).each { count ->
doit(count)
}
}
houston { println it }
new File('/x.txt').eachLine {
println it
}
3.times { println 'Hi' }
[0, 1, 2].each { number ->
println number
}
[0, 1, 2].each { println it}
def printit = { println it }
[0, 1, 2].each printit
©ASERT2006-2013
Better Design Patterns: Builder
<html>
<head>
<title>Hello</title>
</head>
<body>
<ul>
<li>world 1</li>
<li>world 2</li>
<li>world 3</li>
<li>world 4</li>
<li>world 5</li>
</ul>
</body>
</html>
import groovy.xml.*
def page = new MarkupBuilder()
page.html {
head { title 'Hello' }
body {
ul {
for (count in 1..5) {
li "world $count"
} } } }
• Markup Builder
...Better File Manipulation
©ASERT2006-2013
def out = new File('result.txt')
out.delete()
new File('..').eachFileRecurse { file ->
if (file.name.endsWith('.groovy')) {
file.eachLine { line, num ->
if (line.toLowerCase().contains('groovy'))
out << "File '$file' on line $numn$linen"
}
}
}
...DSL example...
©ASERT2006-2013
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
Inspiration for this example came from …
...DSL example
©ASERT2006-2013
// Japanese DSL using GEP3 rules
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
interface Calc {
def execute(n, m)
}
class CalcByMult implements Calc {
def execute(n, m) { n * m }
}
class CalcByManyAdds implements Calc {
def execute(n, m) {
def result = 0
n.times {
result += m
}
return result
}
}
def sampleData = [
[3, 4, 12],
[5, -5, -25]
]
Calc[] multiplicationStrategies = [
new CalcByMult(),
new CalcByManyAdds()
]
sampleData.each {data ->
multiplicationStrategies.each {calc ->
assert data[2] == calc.execute(data[0], data[1])
}
}
def multiplicationStrategies = [
{ n, m -> n * m },
{ n, m ->
def total = 0; n.times{ total += m }; total },
{ n, m -> ([m] * n).sum() }
]
def sampleData = [
[3, 4, 12],
[5, -5, -25]
]
sampleData.each{ data ->
multiplicationStrategies.each{ calc ->
assert data[2] == calc(data[0], data[1])
}
}
Language features instead of Patterns
(c)ASERT2006-2013
Strategy Pattern
with interfaces
with closures
Topics
• Intro to Functional Style
Functional Basics
• Immutability & Persistent Data Structures
• Laziness & Strictness
• GPars & Concurrency
• Type Safety
• Word Split (bonus material)
• More Info
©ASERT2006-2013
Pure Functions, Closures, Side-effects
©ASERT2006-2013
def x = 4
def increment = { arg -> arg + 1 }
assert 11 == increment (10)
assert x == 4
def incrementWithSideEffect = { arg -> x++; arg + 1 }
assert 11 == incrementWithSideEffect(10)
assert 101 == incrementWithSideEffect(100)
assert x == 6
Referential Transparency
©ASERT2006-2013
def x, y, z, arg
def method = {
// ...
}
y = 3
arg = y
x = y + 1
method(arg)
z = y + 1 // z = x
assert x == z
def pythagorian(x, y) { Math.sqrt(x * x + y * y) }
final int A = 4
final int B = 3
def c = pythagorian(A, B) // c = 5
assert c == 5
Show me the code
PrimesPalindromes.groovy, Composition.groovy, Memoize.groovy, FactorialTrampoline.groovy
Tail Recursion
• https://github.com/jlink/tailrec
©ASERT2006-2013
@TailRecursive
def factorial(n, acc = 1) {
n <= 1 ? acc : factorial(n - 1, n * acc)
}
println factorial(1000G)
Topics
• Intro to Functional Style
• Functional Basics
Immutability & Persistent Data Structures
• Laziness & Strictness
• GPars & Concurrency
• Type Safety
• Word Split (bonus material)
• More Info
©ASERT2006-2013
Immutability
• An object’s value doesn’t change once created
• Examples
– Groovy has primitives & their wrapper classes,
Strings, null
– “constants” (final reference fields)
• With some caveats about what they point to
– Basic enum values
• With some caveats on complex enums
– Numerous (effectively) immutable classes
• java.awt.Color, java.net.URI, java.util.UUID, java.lang.Class,
java.util.Date, java.math.BigInteger, java.math.BigDecimal
– Your own carefully written classes
– Very careful use of aggregation/collection classes
– Special immutable aggregation/collection classes
Why Immutability?
• Simple
– Exactly one state
– Potentially easier to design, implement, use, reason
about & make secure
• Inherently referentially transparent
– Potential for optimisation
• Can be shared freely
– Including “constant” aggregations of immutables
– Including persistent structures of immutables
– Suitable for caching
– Can even cache “pure” expressions involving
immutables, e.g. 3 + 4, “string”.size(), fib(42)
– Inherently thread safe
Approaches to managing collection storage
• Mutable • Persistent
©ASERT2006-2013
• Immutable
‘c’ ‘a’ ‘c’ ‘a’
Add ‘t’ Add ‘t’ Add ‘t’
‘c’ ‘a’ ‘t’
‘c’ ‘a’
‘c’ ‘a’ ‘t’
X
‘c’
‘a’
‘t’
‘c’
‘a’
Approaches to managing collection storage
• Mutable • Persistent
©ASERT2006-2013
• Immutable
‘c’ ‘a’ ‘c’ ‘a’
Add ‘t’ Add ‘t’ Add ‘t’
‘c’ ‘a’ ‘t’
‘c’ ‘a’
‘c’ ‘a’ ‘t’
X
‘c’
‘a’
‘t’
‘c’
‘a’
Immutable practices
• Using mutating style
String invention = 'Mouse Trap'
List inventions = [invention]
invention = 'Better ' + invention
inventions << invention
assert inventions == ['Mouse Trap', 'Better Mouse Trap']
inventions.removeAll 'Mouse Trap'
assert inventions == ['Better Mouse Trap']
Immutable practices
• Using mutating style
– We could possibly get away with this code here but it
has some debatable code smells
• (1) add a reference to a mutable list
• (2) change string reference losing original
• (3),(4) mutate list
• (4) duplicate first invention because original lost
String invention = 'Mouse Trap'
List inventions = [invention] //(1)
invention = 'Better ' + invention //(2)
inventions << invention //(3)
assert inventions == ['Mouse Trap', 'Better Mouse Trap']
inventions.removeAll 'Mouse Trap' //(4)
assert inventions == ['Better Mouse Trap']
Approaches to managing collection storage
• Mutable • Persistent
©ASERT2006-2013
• Immutable
‘c’ ‘a’ ‘c’ ‘a’
Add ‘t’ Add ‘t’ Add ‘t’
‘c’ ‘a’ ‘t’
‘c’ ‘a’
‘c’ ‘a’ ‘t’
X
‘c’
‘a’
‘t’
‘c’
‘a’
Immutable practices
• Avoid using mutator methods
Avoid Prefer
list.sort() list.sort(false)
list.unique() list.unique(false)
list.reverse(true) list.reverse()
list.addAll list.plus
list.removeAll list.minus
String or List += or << use differently named variables
mutating java.util.Collections
void methods, e.g. shuffle, swap,
fill, copy, rotate
your own non mutating variants
Immutable practices
• Avoid using mutator methods
Avoid Prefer
list.sort() list.sort(false)
list.unique() list.unique(false)
list.reverse(true) list.reverse()
list.addAll list.plus
list.removeAll list.minus
String or List += or << use differently named variables
mutating java.util.Collections
void methods, e.g. shuffle, swap,
fill, copy, rotate
your own non mutating variants
public class Collections {
public static void shuffle(List<?> list) { /* ... */ }
/* ... */
}
Immutable practices
• Avoid using mutator methods
Avoid Prefer
list.sort() list.sort(false)
list.unique() list.unique(false)
list.reverse(true) list.reverse()
list.addAll list.plus
list.removeAll list.minus
String or List += or << use differently named variables
mutating java.util.Collections
void methods, e.g. shuffle, swap,
fill, copy, rotate
your own non mutating variants
static List myShuffle(List list) {
List result = new ArrayList(list)
Collections.shuffle(result)
result
}
Immutable practices
• Avoid using mutator methods
– But only marginal gains when using Java’s built-in
collections
// Avoid
String invention = 'Mouse Trap'
List inventions = [invention]
invention = 'Better ' + invention
inventions << invention
assert inventions == ['Mouse Trap', 'Better Mouse Trap']
inventions.removeAll 'Mouse Trap'
assert inventions == ['Better Mouse Trap']
// Prefer
String firstInvention = 'Mouse Trap'
List initialInventions = [firstInvention]
String secondInvention = 'Better ' + firstInvention
List allInventions = initialInventions + secondInvention
assert allInventions == ['Mouse Trap', 'Better Mouse Trap']
List bestInventions = allInventions - firstInvention
assert bestInventions == ['Better Mouse Trap']
Immutability options - collections
• Built-in
• Google Collections
– Numerous improved immutable collection types
• Groovy run-time metaprogramming
import com.google.common.collect.*
List<String> animals = ImmutableList.of("cat", "dog", "horse")
animals << 'fish' // => java.lang.UnsupportedOperationException
def animals = ['cat', 'dog', 'horse'].asImmutable()
animals << 'fish' // => java.lang.UnsupportedOperationException
def animals = ['cat', 'dog', 'horse']
ArrayList.metaClass.leftShift = {
throw new UnsupportedOperationException() }
animals << 'fish' // => java.lang.UnsupportedOperationException
Approaches to managing collection storage
• Mutable • Persistent
©ASERT2006-2013
• Immutable
‘c’ ‘a’ ‘c’ ‘a’
Add ‘t’ Add ‘t’ Add ‘t’
‘c’ ‘a’ ‘t’
‘c’ ‘a’
‘c’ ‘a’ ‘t’
X
‘c’
‘a’
‘t’
‘c’
‘a’
Immutability – persistent collections
• Functional Java
– Or Functional Groovy, clj-ds, pcollections, totallylazy
@Grab('org.functionaljava:functionaljava:3.1')
def pets = fj.data.List.list("cat", "dog", "horse")
// buy a fish
def newPets = pets.cons("fish")
assert [3, 4] == [pets.length(), newPets.length()]
pets
newPets
head
tail
head
tail
head
tail
head
tail
fish
cat
dog
horse
Immutability – persistent collections
• Functional Java
@Grab('org.functionaljava:functionaljava:3.1')
def pets = fj.data.List.list("cat", "dog", "horse")
def newPets = pets.cons("fish")
assert [3, 4] == [pets.length(), newPets.length()]
// sell the horse
def remaining = newPets.removeAll{ it == 'horse' }
pets
newPets
head
tail
head
tailhead
tail
head
tail
fish
cat
dog
horse
remaining
???
Immutability – persistent collections
• Functional Java
@Grab('org.functionaljava:functionaljava:3.1')
def pets = fj.data.List.list("cat", "dog", "horse")
def newPets = pets.cons("fish")
assert [3, 4] == [pets.length(), newPets.length()]
def remaining = newPets.removeAll{ it == 'horse' }
assert [3, 4, 3] == [pets, newPets, remaining]*.length()
pets
newPets
head
tail
head
tailhead
tail
head
tail
fish
cat
dog
horse
remaining
???
Immutability – persistent collections
• Functional Java
@Grab('org.functionaljava:functionaljava:3.1')
def pets = fj.data.List.list("cat", "dog", "horse")
def newPets = pets.cons("fish")
assert [3, 4] == [pets.length(), newPets.length()]
def remaining = newPets.removeAll{ it == 'horse' }
assert [3, 4, 3] == [pets, newPets, remaining]*.length()
pets
newPets
head
tail
head
tailhead
tail
head
tail
fish
cat
dog
horse
remaining
head
tail
head
tail
head
tail
fish
cat
dog
copy
copy
copy
Immutability – persistent collections
A
B C
D E F G
H I K
???
J
original
Immutability – persistent collections
• You will see the correct results but in general, different
operations may give very differing performance
characteristics from what you expect
– But don’t fret, smart people are working on smart structures to support a variety
of scenarios. You may even have several in your current NoSQL implementation
A
B C
D E F G
H I
A*
C*
G*
KJ
original modified
Reality check
• OK, do I have to write this myself?
– Might pay to try some simple ones. Take a look at Eric
Lippert’s blog on some C# implementations. Here is
the first part (Part 1: Kinds of Immutability):
http://blogs.msdn.com/ericlippert/archive/2007/11/13/
immutability-in-c-part-one-kinds-of-immutability.aspx
– Also consider
• Part 2: Simple Immutable Stack, Part 3: Covariant Immutable
Stack, Part 4: Immutable Queue, Part 6: Simple Binary Tree
– There are probably plenty of implementations you can
already use
– See also: Purely Functional Data Structures by Chris
Okasak, Cambridge University Press (1999)
• It turns out you use trees for nearly everything! 
Reality check
• Functional Java persistent data structures
– Singly-linked list (fj.data.List)
– Lazy singly-linked list (fj.data.Stream)
– Nonempty list (fj.data.NonEmptyList)
– Optional value (a container of length 0 or 1) (fj.data.Option)
– Immutable set using a red/black tree (fj.data.Set)
– Immutable multi-way tree (a.k.a. rose tree) (fj.data.Tree)
– Immutable tree-map using a red/black tree (fj.data.TreeMap)
– Products (tuples) of arity 1-8 (fj.P1..P8)
– Vectors of arity 2-8 (fj.data.vector.V2..V8)
– Pointed lists and trees (fj.data.Zipper and fj.data.TreeZipper)
– Type-safe, generic heterogeneous list (fj.data.hlist.HList)
– Immutable arrays (fj.data.Array)
– Disjoint union datatype (fj.data.Either)
– 2-3 finger trees supporting access to the ends in amortized O(1)
time (fj.data.fingertrees)
Reality check
• OK, have we achieved something simpler?
– It depends. Understanding the insides of persistent
data structures can be very hard
• But as you move towards more complex systems and more
concurrent systems, not having to worry about which
threads are mutating what and when usually outweighs the
complexities of using persistent data structures
• Arguing for impure in Haskell:
http://www.cse.unsw.edu.au/~benl/papers/thesis/lippmeier-
impure-world.pdf
– They still don’t solve all of the problems. For any
significant problem you will have multiple threads
working on the solution. In some sense we have just
moved the problem but at least we have separated
concerns.
• You might combine with message passing (actors) or
dataflow or software transactional memory (STM)
Immutable Classes
• Some Rules
– Don’t provide mutators
– Ensure that no methods can
be overridden
• Easiest to make the class final
• Or use static factories & non-public
constructors
– Make all fields final
– Make all fields private
• Avoid even public immutable constants
– Ensure exclusive access to any mutable components
• Don’t leak internal references
• Defensive copying in and out
– Optionally provide equals and hashCode methods
– Optionally provide toString method
@Immutable...
• Java Immutable Class
– As per Joshua Bloch
Effective Java
©ASERT2006-2013
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...
• Java Immutable Class
– As per Joshua Bloch
Effective Java
©ASERT2006-2013
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
...@Immutable
©ASERT2006-2013
@Immutable class Person {
String first, last
}
Topics
• Intro to Functional Style
• Functional Basics
• Immutability & Persistent Data Structures
Laziness & Strictness
• GPars & Concurrency
• Type Safety
• Word Split (bonus material)
• More Info
©ASERT2006-2013
totallylazy library
• Similar to Groovy’s collection
GDK methods …
• Except … lazy …
@GrabResolver('http://repo.bodar.com/')
@Grab('com.googlecode.totallylazy:totallylazy:1113')
import static com.googlecode.totallylazy.Sequences.map
import static com.googlecode.totallylazy.numbers.Numbers.*
assert range(6, 10) == [6,7,8,9,10]
assert range(6, 10, 2).forAll(even)
assert range(6, 10).reduce{ a, b -> a + b } == 40
assert range(6, 10).foldLeft(0, add) == 40
assert map(range(6, 10), { it + 100 }) == [106,107,108,109,110]
assert primes().take(10) == [2,3,5,7,11,13,17,19,23,29]
assert range(1, 4).cycle().drop(2).take(8) == [3,4,1,2,3,4,1,2]
println range(6, 1_000_000_000_000).filter(even).drop(1).take(5)
// => 8,10,12,14,16 (a handful of millis later)
Immutability options - collections
• This script
• Produces this output (order will vary)
@GrabResolver('http://repo.bodar.com/')
@Grab('com.googlecode.totallylazy:totallylazy:1113')
import static com.googlecode.totallylazy.Sequences.flatMapConcurrently
import static com.googlecode.totallylazy.numbers.Numbers.*
println flatMapConcurrently(range(6, 10)) {
println it // just for logging
even(it) ? [it, it+100] : []
}
//9
//7
//8
//6
//10
//6,106,8,108,10,110
GPars and TotallyLazy library
©ASERT2006-2013
@GrabResolver('http://repo.bodar.com')
@Grab('com.googlecode.totallylazy:totallylazy:1113')
import static groovyx.gpars.GParsExecutorsPool.withPool
import static com.googlecode.totallylazy.Callables.asString
import static com.googlecode.totallylazy.Sequences.sequence
withPool { pool ->
assert ['5', '6'] == sequence(4, 5, 6)
.drop(1)
.mapConcurrently(asString(), pool)
.toList()
}
withPool {
assert ['5', '6'] == [4, 5, 6]
.drop(1)
.collectParallel{ it.toString() }
}
<= Plain GPars equivalent
Groovy Streams
• https://github.com/timyates/groovy-stream
@Grab('com.bloidonia:groovy-stream:0.5.2')
import groovy.stream.Stream
// Repeat an object indefinitely
Stream s = Stream.from { 1 }
assert s.take( 5 ).collect() == [ 1, 1, 1, 1, 1 ]
// Use an Iterable
s = Stream.from 1..3
assert s.collect() == [ 1, 2, 3 ]
// Use an iterator
def iter = [ 1, 2, 3 ].iterator()
s = Stream.from iter
assert s.collect() == [ 1, 2, 3 ]
// Use a map of iterables
s = Stream.from x:1..2, y:3..4
assert s.collect() == [ [x:1,y:3],[x:1,y:4],[x:2,y:3],[x:2,y:4] ]
Groovy Streams
• https://github.com/dsrkoc/monadologie
import static hr.helix.monadologie.MonadComprehension.foreach
def res = foreach {
a = takeFrom { [1, 2, 3] }
b = takeFrom { [4, 5] }
yield { a + b }
}
assert res == [5, 6, 6, 7, 7, 8]
Functional Groovy
• https://github.com/mperry/functionalgroovy
@GrabResolver('https://oss.sonatype.org/content/groups/public')
@Grab('com.github.mperry:functionalgroovy-core:0.2-SNAPSHOT')
@Grab('org.functionaljava:functionaljava:3.1')
import static com.github.mperry.fg.Comprehension.foreach
1.to(5).each { println it }
def result = foreach {
num { 1.to(2) }
yield { num + 1 }
}
assert result.toJList() == [2, 3]
Show me the code
LazyMain.groovy
Topics
• Intro to Functional Style
• Functional Basics
• Immutability & Persistent Data Structures
• Laziness & Strictness
GPars & Concurrency
• Type Safety
• Word Split (bonus material)
• More Info
©ASERT2006-2013
Ralph Johnson: Parallel Programming
• Styles of parallel programming
– Threads and locks
• Nondeterministic, low-level, rumored humans can do this
– Asynchronous messages e.g. Actors –
no or limited shared memory
• Nondeterministic, ok for I/O but be careful with side-effects
– Sharing with deterministic restrictions
e.g. Fork-join
• Hopefully deterministic semantics, not designed for I/O
– Data parallelism
• Deterministic semantics, easy, efficient, not designed for I/O
©ASERT2006-2013
http://strangeloop2010.com/talk/presentation_file/14485/Johnson-DataParallelism.pdf
Each approach has some caveats
GPars
• http://gpars.codehaus.org/
• Library classes and DSL sugar providing
intuitive ways for Groovy developers to
handle tasks concurrently. Logical parts:
– Data Parallelism features use JSR-166y Parallel Arrays
to enable multi-threaded collection processing
– Asynchronous functions extend the Java 1.5 built-in
support for executor services to enable multi-threaded
closure processing
– Dataflow Concurrency supports natural shared-memory
concurrency model, using single-assignment variables
– Actors provide an implementation of Erlang/Scala-like
actors including "remote" actors on other machines
– Safe Agents provide a non-blocking mt-safe reference to
mutable state; inspired by "agents" in Clojure
©ASERT2006-2013
Coordination approachesSource:ReGinA–GroovyinAction,2ndedition
Data Parallelism:
Fork/Join
Map/Reduce
Fixed coordination
(for collections)
Actors Explicit coordination
Safe Agents Delegated coordination
Dataflow Implicit coordination
GPars: Choosing approachesFormoredetailssee:http://gpars.codehaus.org/Concepts+compared
Parallel
Collections
Data Parallelism
Task
Parallelism
Streamed Data
Parallelism
Fork/
Join
Dataflow
operators
CSP
Actors
Dataflow tasks
Actors
Asynch fun’s
CSP
Fork/
Join
Immutable
Stm, Agents
Special collections
Synchronization
Linear Recursive
Linear
Recursive
Shared
Data
Irregular
Regular
Groovy Sequential Collection
©ASERT2006-2013
def oneStarters = (1..30)
.collect { it ** 2 }
.findAll { it ==~ '1.*' }
assert oneStarters == [1, 16, 100, 121, 144, 169, 196]
assert oneStarters.max() == 196
assert oneStarters.sum() == 747
GPars Parallel Collections…
©ASERT2006-2013
import static groovyx.gpars.GParsPool.withPool
withPool {
def oneStarters = (1..30)
.collectParallel { it ** 2 }
.findAllParallel { it ==~ '1.*' }
assert oneStarters == [1, 16, 100, 121, 144, 169, 196]
assert oneStarters.maxParallel() == 196
assert oneStarters.sumParallel() == 747
}
…GPars Parallel Collections
• Suitable when
– Each iteration is independent, i.e. not:
fact[index] = index * fact[index - 1]
– Iteration logic doesn’t use non-thread safe code
– Size and indexing of iteration are important
©ASERT2006-2013
import static groovyx.gpars.GParsPool.withPool
withPool {
def oneStarters = (1..30)
.collectParallel { it ** 2 }
.findAllParallel { it ==~ '1.*' }
assert oneStarters == [1, 16, 100, 121, 144, 169, 196]
assert oneStarters.maxParallel() == 196
assert oneStarters.sumParallel() == 747
}
Parallel Collection Variations
• Apply some Groovy metaprogramming
©ASERT2006-2013
import static groovyx.gpars.GParsPool.withPool
withPool {
def oneStarters = (1..30).makeConcurrent()
.collect { it ** 2 }
.findAll { it ==~ '1.*' }
.findAll { it ==~ '...' }
assert oneStarters == [100, 121, 144, 169, 196]
}
import groovyx.gpars.ParallelEnhancer
def nums = 1..5
ParallelEnhancer.enhanceInstance(nums)
assert [1, 4, 9, 16, 25] == nums.collectParallel{ it * it }
GPars parallel methods for collections
Transparent Transitive? Parallel Lazy?
any { ... } anyParallel { ... } yes
collect { ... } yes collectParallel { ... }
count(filter) countParallel(filter)
each { ... } eachParallel { ... }
eachWithIndex { ... } eachWithIndexParallel { ... }
every { ... } everyParallel { ... } yes
find { ... } findParallel { ... }
findAll { ... } yes findAllParallel { ... }
findAny { ... } findAnyParallel { ... }
fold { ... } foldParallel { ... }
fold(seed) { ... } foldParallel(seed) { ... }
grep(filter) yes grepParallel(filter)
groupBy { ... } groupByParallel { ... }
max { ... } maxParallel { ... }
max() maxParallel()
min { ... } minParallel { ... }
min() minParallel()
split { ... } yes splitParallel { ... }
sum sumParallel // foldParallel +
Transitive means result is automatically transparent; Lazy means fails fast
FormoredetailsseeReGinAortheGParsdocumentation
GPars: Map-Reduce
©ASERT2006-2013
import static groovyx.gpars.GParsPool.withPool
withPool {
def oneStarters = (1..30).parallel
.map { it ** 2 }
.filter { it ==~ '1.*' }
assert oneStarters.collection ==
[1, 16, 100, 121, 144, 169, 196]
// aggregations/reductions
assert oneStarters.max() == 196
assert oneStarters.reduce { a, b -> a + b } == 747
assert oneStarters.sum() == 747
}
GPars parallel array methods
Method Return Type
combine(initValue) { ... } Map
filter { ... } Parallel array
collection Collection
groupBy { ... } Map
map { ... } Parallel array
max() T
max { ... } T
min() T
min { ... } T
reduce { ... } T
reduce(seed) { ... } T
size() int
sort { ... } Parallel array
sum() T
parallel // on a Collection Parallel array
FormoredetailsseeReGinAortheGParsdocumentation
Parallel Collections vs Map-Reduce
Fork Fork
JoinJoin
Map
Map
Reduce
Map
Map
Reduce
Reduce
Map
Filter
FilterMap
Concurrency challenge…
• Suppose we have the following
calculation involving several functions:
• And we want to use our available cores …
©ASERT2006-2013
// example adapted from Parallel Programming with .Net
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:
©ASERT2006-2013
// example adapted from Parallel Programming with .Net
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:
©ASERT2006-2013
// example adapted from Parallel Programming with .Net
def (f1, f2, f3, f4) = [{ sleep 1000; it }] * 3 +
[{ x, y -> x + y }]
import static groovyx.gpars.GParsPool.withPool
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
b
c
d
f
…Concurrency challenge
• And with GPars Dataflows:
©ASERT2006-2013
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:
©ASERT2006-2013
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
GPars: Dataflows...
©ASERT2006-2013
import groovyx.gpars.dataflow.DataFlows
import static groovyx.gpars.dataflow.DataFlow.task
final flow = new DataFlows()
task { flow.result = flow.x + flow.y }
task { flow.x = 10 }
task { flow.y = 5 }
assert 15 == flow.result
new DataFlows().with {
task { result = x * y }
task { x = 10 }
task { y = 5 }
assert 50 == result
}
510
yx
*
...GPars: Dataflows...
• Evaluating:
©ASERT2006-2013
import groovyx.gpars.dataflow.DataFlows
import static groovyx.gpars.dataflow.DataFlow.task
final flow = new DataFlows()
task { flow.a = 10 }
task { flow.b = 5 }
task { flow.x = flow.a - flow.b }
task { flow.y = flow.a + flow.b }
task { flow.result = flow.x * flow.y }
assert flow.result == 75
b
10 5
a
+-
*
result = (a – b) * (a + b)
x y
Question: what happens if I change the order of the task statements here?
...GPars: Dataflows...
• Naive attempt for loops
©ASERT2006-2013
import groovyx.gpars.dataflow.Dataflows
import static groovyx.gpars.dataflow.Dataflow.task
final flow = new Dataflows()
[10, 20].each { thisA ->
[4, 5].each { thisB ->
task { flow.a = thisA }
task { flow.b = thisB }
task { flow.x = flow.a - flow.b }
task { flow.y = flow.a + flow.b }
task { flow.result = flow.x * flow.y }
println flow.result
}
}
// => java.lang.IllegalStateException:
A DataflowVariable can only be assigned once.
...
task { flow.a = 10 }
...
task { flow.a = 20 }
Don’t do this!
X
...GPars: Dataflows...
©ASERT2006-2013
import groovyx.gpars.dataflow.DataflowStream
import static groovyx.gpars.dataflow.Dataflow.*
final streamA = new DataflowStream()
final streamB = new DataflowStream()
final streamX = new DataflowStream()
final streamY = new DataflowStream()
final results = new DataflowStream()
operator(inputs: [streamA, streamB],
outputs: [streamX, streamY]) {
a, b -> streamX << a - b; streamY << a + b
}
operator(inputs: [streamX, streamY],
outputs: [results]) { x, y -> results << x * y }
[[10, 20], [4, 5]].combinations().each{ thisA, thisB ->
task { streamA << thisA }
task { streamB << thisB }
}
4.times { println results.val }
b
10
10
20
20
4
5
4
5
a
+-
*
84
75
384
375
...GPars: Dataflows
• Suitable when:
– Your algorithms can be expressed as mutually-
independent logical tasks
• Properties:
– Inherently safe and robust (no race conditions or
livelocks)
– Amenable to static analysis
– Deadlocks “typically” become repeatable
– “Beautiful” (declarative) code
©ASERT2006-2013
import groovyx.gpars.dataflow.Dataflows
import static groovyx.gpars.dataflow.Dataflow.task
final flow = new Dataflows()
task { flow.x = flow.y }
task { flow.y = flow.x }
…GPars: Actors...
©ASERT2006-2013
import static groovyx.gpars.actor.Actors.*
def votes = reactor {
it.endsWith('y') ? "You voted for $it" : "Sorry, please try again"
}
println votes.sendAndWait('Groovy')
println votes.sendAndWait('JRuby')
println votes.sendAndWait('Go')
def languages = ['Groovy', 'Dart', 'C++']
def booth = actor {
languages.each{ votes << it }
loop {
languages.size().times {
react { println it }
}
stop()
}
}
booth.join(); votes.stop(); votes.join()
You voted for Groovy
You voted for JRuby
Sorry, please try again
You voted for Groovy
Sorry, please try again
Sorry, please try again
Software Transactional Memory…
©ASERT2006-2013
@Grab('org.multiverse:multiverse-beta:0.7-RC-1')
import org.multiverse.api.references.LongRef
import static groovyx.gpars.stm.GParsStm.atomic
import static org.multiverse.api.StmUtils.newLongRef
class Account {
private final LongRef balance
Account(long initial) {
balance = newLongRef(initial)
}
void setBalance(long newBalance) {
if (newBalance < 0) throw new RuntimeException("not enough money")
balance.set newBalance
}
long getBalance() {
balance.get()
}
}
// ...
…Software Transactional Memory
©ASERT2006-2013
// ...
def from = new Account(20)
def to = new Account(20)
def amount = 10
def watcher = Thread.start {
15.times {
atomic { println "from: ${from.balance}, to: ${to.balance}" }
sleep 100
}
}
sleep 150
try {
atomic {
from.balance -= amount
to.balance += amount
sleep 500
}
println 'transfer success'
} catch(all) {
println all.message
}
atomic { println "from: $from.balance, to: $to.balance" }
watcher.join()
Topics
• Intro to Functional Style
• Functional Basics
• Immutability & Persistent Data Structures
• Laziness & Strictness
• GPars & Concurrency
Type Safety
• Word Split (bonus material)
• More Info
©ASERT2006-2013
Show me the code
JScience, SPrintfChecker, GenericStackTest
Topics
• Intro to Functional Style
• Functional Basics
• Immutability & Persistent Data Structures
• Laziness & Strictness
• GPars & Concurrency
• Type Safety
Word Split (bonus material)
• More Info
©ASERT2006-2013
Word Split with Fortress
©ASERT2006-2013
Guy Steele’s StrangeLoop keynote (from slide 52 onwards for several slides):
http://strangeloop2010.com/talk/presentation_file/14299/GuySteele-parallel.pdf
Word Split…
©ASERT2006-2013
def swords = { s ->
def result = []
def word = ''
s.each{ ch ->
if (ch == ' ') {
if (word) result += word
word = ''
} else word += ch
}
if (word) result += word
result
}
assert swords("This is a sample") == ['This', 'is', 'a', 'sample']
assert swords("Here is a sesquipedalian string of words") ==
['Here', 'is', 'a', 'sesquipedalian', 'string', 'of', 'words']
Word Split…
©ASERT2006-2013
def swords = { s ->
def result = []
def word = ''
s.each{ ch ->
if (ch == ' ') {
if (word) result += word
word = ''
} else word += ch
}
if (word) result += word
result
}
Word Split…
©ASERT2006-2013
def swords = { s ->
def result = []
def word = ''
s.each{ ch ->
if (ch == ' ') {
if (word) result += word
word = ''
} else word += ch
}
if (word) result += word
result
}
…Word Split…
©ASERT2006-2013
…Word Split…
©ASERT2006-2013
Segment(left1, m1, right1) Segment(left2, m2, right2)
Segment(left1, m1 + [ ? ] + m2, right2)
…Word Split…
©ASERT2006-2013
…Word Split…
©ASERT2006-2013
class Util { static maybeWord(s) { s ? [s] : [] } }
import static Util.*
@Immutable class Chunk {
String s
public static final ZERO = new Chunk('')
def plus(Chunk other) { new Chunk(s + other.s) }
def plus(Segment other) {
new Segment(s + other.l, other.m, other.r) }
def flatten() { maybeWord(s) }
}
@Immutable class Segment {
String l; List m; String r
public static final ZERO = new Segment('', [], '')
def plus(Chunk other) { new Segment(l, m, r + other.s) }
def plus(Segment other) {
new Segment(l, m + maybeWord(r + other.l) + other.m, other.r) }
def flatten() { maybeWord(l) + m + maybeWord(r) }
}
…Word Split…
©ASERT2006-2013
def processChar(ch) { ch == ' ' ?
new Segment('', [], '') :
new Chunk(ch) }
def swords(s) { s.inject(Chunk.ZERO) { result, ch ->
result + processChar(ch) } }
assert swords("Here is a sesquipedalian string of words").flatten()
== ['Here', 'is', 'a', 'sesquipedalian', 'string', 'of', 'words']
…Word Split…
©ASERT2006-2013
…Word Split…
©ASERT2006-2013
…Word Split…
©ASERT2006-2013
THREADS = 4
def pwords(s) {
int n = (s.size() + THREADS - 1) / THREADS
def map = new ConcurrentHashMap()
(0..<THREADS).collect { i ->
Thread.start {
def (min, max) = [
[s.size(), i * n].min(), [s.size(), (i + 1) * n].min()
]
map[i] = swords(s[min..<max])
}
}*.join()
(0..<THREADS).collect { i -> map[i] }.sum().flatten()
}
…Word Split…
©ASERT2006-2013
import static groovyx.gpars.GParsPool.withPool
THRESHHOLD = 10
def partition(piece) {
piece.size() <= THRESHHOLD ? piece :
[piece[0..<THRESHHOLD]] + partition(piece.substring(THRESHHOLD))
}
def pwords = { input ->
withPool(THREADS) {
partition(input).parallel.map(swords).reduce{ a, b -> a + b }.flatten()
}
}
…Guy Steele example in Groovy…
©ASERT2006-2013
def words = { s ->
int n = (s.size() + THREADS - 1) / THREADS
def min = (0..<THREADS).collectEntries{ [it, [s.size(),it*n].min()] }
def max = (0..<THREADS).collectEntries{ [it, [s.size(),(it+1)*n].min()] }
def result = new DataFlows().with {
task { a = swords(s[min[0]..<max[0]]) }
task { b = swords(s[min[1]..<max[1]]) }
task { c = swords(s[min[2]..<max[2]]) }
task { d = swords(s[min[3]..<max[3]]) }
task { sum1 = a + b }
task { sum2 = c + d }
task { sum = sum1 + sum2 }
println 'Tasks ahoy!'
sum
}
switch(result) {
case Chunk: return maybeWord(result.s)
case Segment: return result.with{ maybeWord(l) + m + maybeWord(r) }
}
}
DataFlow version: partially hard-coded to 4 partitions for easier reading
…Guy Steele example in Groovy…
©ASERT2006-2013
GRANULARITY_THRESHHOLD = 10
THREADS = 4
println GParsPool.withPool(THREADS) {
def result = runForkJoin(0, input.size(), input){ first, last, s ->
def size = last - first
if (size <= GRANULARITY_THRESHHOLD) {
swords(s[first..<last])
} else { // divide and conquer
def mid = first + ((last - first) >> 1)
forkOffChild(first, mid, s)
forkOffChild(mid, last, s)
childrenResults.sum()
}
}
switch(result) {
case Chunk: return maybeWord(result.s)
case Segment: return result.with{ maybeWord(l) + m + maybeWord(r) }
}
}
Fork/Join version
…Guy Steele example in Groovy
©ASERT2006-2013
println GParsPool.withPool(THREADS) {
def ans = input.collectParallel{ processChar(it) }.sum()
switch(ans) {
case Chunk: return maybeWord(ans.s)
case Segment: return ans.with{ maybeWord(l) + m + maybeWord(r) }
}
}
Just leveraging the algorithm’s parallel nature
Topics
• Intro to Functional Style
• Functional Basics
• Immutability & Persistent Data Structures
• Laziness & Strictness
• GPars & Concurrency
• Type Safety
• Word Split (bonus material)
More Info
©ASERT2006-2013
More Information: Groovy in Action

Weitere ähnliche Inhalte

Was ist angesagt?

Expression trees in C#
Expression trees in C#Expression trees in C#
Expression trees in C#Oleksii Holub
 
Oleksii Holub "Expression trees in C#"
Oleksii Holub "Expression trees in C#" Oleksii Holub "Expression trees in C#"
Oleksii Holub "Expression trees in C#" Fwdays
 
Polyglot Programming in the JVM
Polyglot Programming in the JVMPolyglot Programming in the JVM
Polyglot Programming in the JVMAndres Almiray
 
GPars (Groovy Parallel Systems)
GPars (Groovy Parallel Systems)GPars (Groovy Parallel Systems)
GPars (Groovy Parallel Systems)Gagan Agrawal
 
Logic programming a ruby perspective
Logic programming a ruby perspectiveLogic programming a ruby perspective
Logic programming a ruby perspectiveNorman Richards
 
Gpars concepts explained
Gpars concepts explainedGpars concepts explained
Gpars concepts explainedVaclav Pech
 
CS101- Introduction to Computing- Lecture 26
CS101- Introduction to Computing- Lecture 26CS101- Introduction to Computing- Lecture 26
CS101- Introduction to Computing- Lecture 26Bilal Ahmed
 
POLITEKNIK MALAYSIA
POLITEKNIK MALAYSIAPOLITEKNIK MALAYSIA
POLITEKNIK MALAYSIAAiman Hud
 
Scala - en bedre og mere effektiv Java?
Scala - en bedre og mere effektiv Java?Scala - en bedre og mere effektiv Java?
Scala - en bedre og mere effektiv Java?Jesper Kamstrup Linnet
 
Designing with Groovy Traits - Gr8Conf India
Designing with Groovy Traits - Gr8Conf IndiaDesigning with Groovy Traits - Gr8Conf India
Designing with Groovy Traits - Gr8Conf IndiaNaresha K
 
python beginner talk slide
python beginner talk slidepython beginner talk slide
python beginner talk slidejonycse
 
Make Testing Groovy
Make Testing GroovyMake Testing Groovy
Make Testing GroovyPaul King
 
Java → kotlin: Tests Made Simple
Java → kotlin: Tests Made SimpleJava → kotlin: Tests Made Simple
Java → kotlin: Tests Made Simpleleonsabr
 
Python tutorial
Python tutorialPython tutorial
Python tutorialRajiv Risi
 
Python tutorialfeb152012
Python tutorialfeb152012Python tutorialfeb152012
Python tutorialfeb152012Shani729
 
Scala for Java programmers
Scala for Java programmersScala for Java programmers
Scala for Java programmers輝 子安
 

Was ist angesagt? (20)

Expression trees in C#
Expression trees in C#Expression trees in C#
Expression trees in C#
 
Oleksii Holub "Expression trees in C#"
Oleksii Holub "Expression trees in C#" Oleksii Holub "Expression trees in C#"
Oleksii Holub "Expression trees in C#"
 
Polyglot Grails
Polyglot GrailsPolyglot Grails
Polyglot Grails
 
Polyglot Programming in the JVM
Polyglot Programming in the JVMPolyglot Programming in the JVM
Polyglot Programming in the JVM
 
GPars (Groovy Parallel Systems)
GPars (Groovy Parallel Systems)GPars (Groovy Parallel Systems)
GPars (Groovy Parallel Systems)
 
Logic programming a ruby perspective
Logic programming a ruby perspectiveLogic programming a ruby perspective
Logic programming a ruby perspective
 
Gpars concepts explained
Gpars concepts explainedGpars concepts explained
Gpars concepts explained
 
CS101- Introduction to Computing- Lecture 26
CS101- Introduction to Computing- Lecture 26CS101- Introduction to Computing- Lecture 26
CS101- Introduction to Computing- Lecture 26
 
POLITEKNIK MALAYSIA
POLITEKNIK MALAYSIAPOLITEKNIK MALAYSIA
POLITEKNIK MALAYSIA
 
Scala - en bedre og mere effektiv Java?
Scala - en bedre og mere effektiv Java?Scala - en bedre og mere effektiv Java?
Scala - en bedre og mere effektiv Java?
 
Designing with Groovy Traits - Gr8Conf India
Designing with Groovy Traits - Gr8Conf IndiaDesigning with Groovy Traits - Gr8Conf India
Designing with Groovy Traits - Gr8Conf India
 
Scala - en bedre Java?
Scala - en bedre Java?Scala - en bedre Java?
Scala - en bedre Java?
 
python beginner talk slide
python beginner talk slidepython beginner talk slide
python beginner talk slide
 
core.logic introduction
core.logic introductioncore.logic introduction
core.logic introduction
 
C# - What's next
C# - What's nextC# - What's next
C# - What's next
 
Make Testing Groovy
Make Testing GroovyMake Testing Groovy
Make Testing Groovy
 
Java → kotlin: Tests Made Simple
Java → kotlin: Tests Made SimpleJava → kotlin: Tests Made Simple
Java → kotlin: Tests Made Simple
 
Python tutorial
Python tutorialPython tutorial
Python tutorial
 
Python tutorialfeb152012
Python tutorialfeb152012Python tutorialfeb152012
Python tutorialfeb152012
 
Scala for Java programmers
Scala for Java programmersScala for Java programmers
Scala for Java programmers
 

Ähnlich wie functional groovy

Migrating from matlab to python
Migrating from matlab to pythonMigrating from matlab to python
Migrating from matlab to pythonActiveState
 
Probabilistic Data Structures (Edmonton Data Science Meetup, March 2018)
Probabilistic Data Structures (Edmonton Data Science Meetup, March 2018)Probabilistic Data Structures (Edmonton Data Science Meetup, March 2018)
Probabilistic Data Structures (Edmonton Data Science Meetup, March 2018)Kyle Davis
 
U-SQL - Azure Data Lake Analytics for Developers
U-SQL - Azure Data Lake Analytics for DevelopersU-SQL - Azure Data Lake Analytics for Developers
U-SQL - Azure Data Lake Analytics for DevelopersMichael Rys
 
Swift, functional programming, and the future of Objective-C
Swift, functional programming, and the future of Objective-CSwift, functional programming, and the future of Objective-C
Swift, functional programming, and the future of Objective-CAlexis Gallagher
 
Alfresco Content Modelling and Policy Behaviours
Alfresco Content Modelling and Policy BehavioursAlfresco Content Modelling and Policy Behaviours
Alfresco Content Modelling and Policy BehavioursJ V
 
Rebuilding Solr 6 examples - layer by layer (LuceneSolrRevolution 2016)
Rebuilding Solr 6 examples - layer by layer (LuceneSolrRevolution 2016)Rebuilding Solr 6 examples - layer by layer (LuceneSolrRevolution 2016)
Rebuilding Solr 6 examples - layer by layer (LuceneSolrRevolution 2016)Alexandre Rafalovitch
 
The Road To Damascus - A Conversion Experience: LotusScript and @Formula to SSJS
The Road To Damascus - A Conversion Experience: LotusScript and @Formula to SSJSThe Road To Damascus - A Conversion Experience: LotusScript and @Formula to SSJS
The Road To Damascus - A Conversion Experience: LotusScript and @Formula to SSJSmfyleman
 
Using Simplicity to Make Hard Big Data Problems Easy
Using Simplicity to Make Hard Big Data Problems EasyUsing Simplicity to Make Hard Big Data Problems Easy
Using Simplicity to Make Hard Big Data Problems Easynathanmarz
 
When assertthat(you).understandUnitTesting() fails
When assertthat(you).understandUnitTesting() failsWhen assertthat(you).understandUnitTesting() fails
When assertthat(you).understandUnitTesting() failsMartin Skurla
 
Scientific Software Development
Scientific Software DevelopmentScientific Software Development
Scientific Software Developmentjalle6
 
Taxonomy of Scala
Taxonomy of ScalaTaxonomy of Scala
Taxonomy of Scalashinolajla
 
Google guava overview
Google guava overviewGoogle guava overview
Google guava overviewSteve Min
 
What's new in Hivemall v0.5.0
What's new in Hivemall v0.5.0What's new in Hivemall v0.5.0
What's new in Hivemall v0.5.0Makoto Yui
 
Introductionto fp with groovy
Introductionto fp with groovyIntroductionto fp with groovy
Introductionto fp with groovyIsuru Samaraweera
 
Introduction to Data Structures & Algorithms
Introduction to Data Structures & AlgorithmsIntroduction to Data Structures & Algorithms
Introduction to Data Structures & AlgorithmsAfaq Mansoor Khan
 
Alfresco Business Reporting - Tech Talk Live 20130501
Alfresco Business Reporting - Tech Talk Live 20130501Alfresco Business Reporting - Tech Talk Live 20130501
Alfresco Business Reporting - Tech Talk Live 20130501Tjarda Peelen
 
The Why and How of Scala at Twitter
The Why and How of Scala at TwitterThe Why and How of Scala at Twitter
The Why and How of Scala at TwitterAlex Payne
 
Software variability management - 2017
Software variability management - 2017Software variability management - 2017
Software variability management - 2017XavierDevroey
 
Functional Domain Modeling - The ZIO 2 Way
Functional Domain Modeling - The ZIO 2 WayFunctional Domain Modeling - The ZIO 2 Way
Functional Domain Modeling - The ZIO 2 WayDebasish Ghosh
 

Ähnlich wie functional groovy (20)

Migrating from matlab to python
Migrating from matlab to pythonMigrating from matlab to python
Migrating from matlab to python
 
Probabilistic Data Structures (Edmonton Data Science Meetup, March 2018)
Probabilistic Data Structures (Edmonton Data Science Meetup, March 2018)Probabilistic Data Structures (Edmonton Data Science Meetup, March 2018)
Probabilistic Data Structures (Edmonton Data Science Meetup, March 2018)
 
U-SQL - Azure Data Lake Analytics for Developers
U-SQL - Azure Data Lake Analytics for DevelopersU-SQL - Azure Data Lake Analytics for Developers
U-SQL - Azure Data Lake Analytics for Developers
 
Swift, functional programming, and the future of Objective-C
Swift, functional programming, and the future of Objective-CSwift, functional programming, and the future of Objective-C
Swift, functional programming, and the future of Objective-C
 
Alfresco Content Modelling and Policy Behaviours
Alfresco Content Modelling and Policy BehavioursAlfresco Content Modelling and Policy Behaviours
Alfresco Content Modelling and Policy Behaviours
 
Rebuilding Solr 6 examples - layer by layer (LuceneSolrRevolution 2016)
Rebuilding Solr 6 examples - layer by layer (LuceneSolrRevolution 2016)Rebuilding Solr 6 examples - layer by layer (LuceneSolrRevolution 2016)
Rebuilding Solr 6 examples - layer by layer (LuceneSolrRevolution 2016)
 
The Road To Damascus - A Conversion Experience: LotusScript and @Formula to SSJS
The Road To Damascus - A Conversion Experience: LotusScript and @Formula to SSJSThe Road To Damascus - A Conversion Experience: LotusScript and @Formula to SSJS
The Road To Damascus - A Conversion Experience: LotusScript and @Formula to SSJS
 
Using Simplicity to Make Hard Big Data Problems Easy
Using Simplicity to Make Hard Big Data Problems EasyUsing Simplicity to Make Hard Big Data Problems Easy
Using Simplicity to Make Hard Big Data Problems Easy
 
When assertthat(you).understandUnitTesting() fails
When assertthat(you).understandUnitTesting() failsWhen assertthat(you).understandUnitTesting() fails
When assertthat(you).understandUnitTesting() fails
 
Scientific Software Development
Scientific Software DevelopmentScientific Software Development
Scientific Software Development
 
Taxonomy of Scala
Taxonomy of ScalaTaxonomy of Scala
Taxonomy of Scala
 
Google guava overview
Google guava overviewGoogle guava overview
Google guava overview
 
What's new in Hivemall v0.5.0
What's new in Hivemall v0.5.0What's new in Hivemall v0.5.0
What's new in Hivemall v0.5.0
 
Introductionto fp with groovy
Introductionto fp with groovyIntroductionto fp with groovy
Introductionto fp with groovy
 
Into The Box 2018 - CBT
Into The Box 2018 - CBTInto The Box 2018 - CBT
Into The Box 2018 - CBT
 
Introduction to Data Structures & Algorithms
Introduction to Data Structures & AlgorithmsIntroduction to Data Structures & Algorithms
Introduction to Data Structures & Algorithms
 
Alfresco Business Reporting - Tech Talk Live 20130501
Alfresco Business Reporting - Tech Talk Live 20130501Alfresco Business Reporting - Tech Talk Live 20130501
Alfresco Business Reporting - Tech Talk Live 20130501
 
The Why and How of Scala at Twitter
The Why and How of Scala at TwitterThe Why and How of Scala at Twitter
The Why and How of Scala at Twitter
 
Software variability management - 2017
Software variability management - 2017Software variability management - 2017
Software variability management - 2017
 
Functional Domain Modeling - The ZIO 2 Way
Functional Domain Modeling - The ZIO 2 WayFunctional Domain Modeling - The ZIO 2 Way
Functional Domain Modeling - The ZIO 2 Way
 

Mehr von Paul King

groovy databases
groovy databasesgroovy databases
groovy databasesPaul King
 
groovy transforms
groovy transformsgroovy transforms
groovy transformsPaul King
 
Agile Testing Practices
Agile Testing PracticesAgile Testing Practices
Agile Testing PracticesPaul King
 
groovy DSLs from beginner to expert
groovy DSLs from beginner to expertgroovy DSLs from beginner to expert
groovy DSLs from beginner to expertPaul King
 
concurrency with GPars
concurrency with GParsconcurrency with GPars
concurrency with GParsPaul King
 
groovy and concurrency
groovy and concurrencygroovy and concurrency
groovy and concurrencyPaul King
 
Dynamic Language Practices
Dynamic Language PracticesDynamic Language Practices
Dynamic Language PracticesPaul King
 
Make Your Builds More Groovy
Make Your Builds More GroovyMake Your Builds More Groovy
Make Your Builds More GroovyPaul King
 
Groovy Power Features
Groovy Power FeaturesGroovy Power Features
Groovy Power FeaturesPaul King
 
Make Your Testing Groovy
Make Your Testing GroovyMake Your Testing Groovy
Make Your Testing GroovyPaul King
 
Groovy Testing Sep2009
Groovy Testing Sep2009Groovy Testing Sep2009
Groovy Testing Sep2009Paul 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
 
Groovy Tutorial
Groovy TutorialGroovy Tutorial
Groovy TutorialPaul 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
 
XML and Web Services with Groovy
XML and Web Services with GroovyXML and Web Services with Groovy
XML and Web Services with GroovyPaul King
 

Mehr von Paul King (16)

groovy databases
groovy databasesgroovy databases
groovy databases
 
groovy transforms
groovy transformsgroovy transforms
groovy transforms
 
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
 
concurrency with GPars
concurrency with GParsconcurrency with GPars
concurrency with GPars
 
groovy and concurrency
groovy and concurrencygroovy and concurrency
groovy and concurrency
 
GroovyDSLs
GroovyDSLsGroovyDSLs
GroovyDSLs
 
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
 
Make Your Testing Groovy
Make Your Testing GroovyMake Your Testing Groovy
Make Your Testing Groovy
 
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 ...
 
Groovy Tutorial
Groovy TutorialGroovy Tutorial
Groovy Tutorial
 
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

"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DayH2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DaySri Ambati
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostZilliz
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningLars Bell
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionDilum Bandara
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 

Kürzlich hochgeladen (20)

"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DayH2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine Tuning
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An Introduction
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 

functional groovy

  • 2. Topics Intro to Functional Style • Functional Basics • Immutability & Persistent Data Structures • Laziness & Strictness • Gpars & Concurrency • Type Safety • Word Split (bonus material) • More Info ©ASERT2006-2013
  • 3. Introduction • What is functional programming? – Favour evaluation of composable expressions over execution of commands – Encourage particular idioms such as side- effect free functions & immutability • And why should I care? – Declarative understandable code – Reduction of errors – Better patterns and approaches to design – Improved reusability – Leverage concurrency ©ASERT2006-2013
  • 4. What makes up functional style? • Functions, Closures, Lambdas, Blocks as first-class citizens • Higher order functions • Mutable vs Immutable data structures • Recursion • Lazy vs Eager evaluation • Declarative vs Imperative style • Advanced Techniques – Memoization, Trampolines, Composition and Curry • Compile-time safety • Concurrency
  • 5. Closures... ©ASERT2006-2013 def twice = { int num -> num + num } assert twice(5) == 10 assert twice.call(6) == 12 def twice10 = { 2 * 10 } assert 20 == twice10() def triple = { arg -> arg * 3 } assert triple(5) == 15 def alsoTriple = { it * 3 } assert alsoTriple(6) == 18 def quadruple = { arg = 2 -> twice(arg) * 2 } assert quadruple(5) == 20 assert quadruple() == 8 // ...
  • 6. ...Closures... ©ASERT2006-2013 // ... def callWith5(Closure c) { c(5) } assert 15 == callWith5(triple) def twiceMethod(int num) { num * 2 } assert twiceMethod(2) == 4 def alsoTwice = this.&twiceMethod assert alsoTwice(5) == 10 def alsoQuadruple = twice >> twice assert alsoQuadruple(5) == 20 def forty = quadruple.curry(10) assert forty() == 40 assert [10, 15, 20] == [twice, triple, quadruple].collect{ it(5) } assert 45 == [alsoTwice, alsoTriple, alsoQuadruple].sum{ it(5) }
  • 7. ...Closures • Used for many things in Groovy: • Iterators • Callbacks • Higher-order functions • Specialized control structures • Dynamic method definition • Resource allocation • Threads • Continuation-like coding ©ASERT2006-2013 def houston(Closure doit) { (10..1).each { count -> doit(count) } } houston { println it } new File('/x.txt').eachLine { println it } 3.times { println 'Hi' } [0, 1, 2].each { number -> println number } [0, 1, 2].each { println it} def printit = { println it } [0, 1, 2].each printit
  • 8. ©ASERT2006-2013 Better Design Patterns: Builder <html> <head> <title>Hello</title> </head> <body> <ul> <li>world 1</li> <li>world 2</li> <li>world 3</li> <li>world 4</li> <li>world 5</li> </ul> </body> </html> import groovy.xml.* def page = new MarkupBuilder() page.html { head { title 'Hello' } body { ul { for (count in 1..5) { li "world $count" } } } } • Markup Builder
  • 9. ...Better File Manipulation ©ASERT2006-2013 def out = new File('result.txt') out.delete() new File('..').eachFileRecurse { file -> if (file.name.endsWith('.groovy')) { file.eachLine { line, num -> if (line.toLowerCase().contains('groovy')) out << "File '$file' on line $numn$linen" } } }
  • 10. ...DSL example... ©ASERT2006-2013 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 Inspiration for this example came from …
  • 11. ...DSL example ©ASERT2006-2013 // Japanese DSL using GEP3 rules 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
  • 12. interface Calc { def execute(n, m) } class CalcByMult implements Calc { def execute(n, m) { n * m } } class CalcByManyAdds implements Calc { def execute(n, m) { def result = 0 n.times { result += m } return result } } def sampleData = [ [3, 4, 12], [5, -5, -25] ] Calc[] multiplicationStrategies = [ new CalcByMult(), new CalcByManyAdds() ] sampleData.each {data -> multiplicationStrategies.each {calc -> assert data[2] == calc.execute(data[0], data[1]) } } def multiplicationStrategies = [ { n, m -> n * m }, { n, m -> def total = 0; n.times{ total += m }; total }, { n, m -> ([m] * n).sum() } ] def sampleData = [ [3, 4, 12], [5, -5, -25] ] sampleData.each{ data -> multiplicationStrategies.each{ calc -> assert data[2] == calc(data[0], data[1]) } } Language features instead of Patterns (c)ASERT2006-2013 Strategy Pattern with interfaces with closures
  • 13. Topics • Intro to Functional Style Functional Basics • Immutability & Persistent Data Structures • Laziness & Strictness • GPars & Concurrency • Type Safety • Word Split (bonus material) • More Info ©ASERT2006-2013
  • 14. Pure Functions, Closures, Side-effects ©ASERT2006-2013 def x = 4 def increment = { arg -> arg + 1 } assert 11 == increment (10) assert x == 4 def incrementWithSideEffect = { arg -> x++; arg + 1 } assert 11 == incrementWithSideEffect(10) assert 101 == incrementWithSideEffect(100) assert x == 6
  • 15. Referential Transparency ©ASERT2006-2013 def x, y, z, arg def method = { // ... } y = 3 arg = y x = y + 1 method(arg) z = y + 1 // z = x assert x == z def pythagorian(x, y) { Math.sqrt(x * x + y * y) } final int A = 4 final int B = 3 def c = pythagorian(A, B) // c = 5 assert c == 5
  • 16. Show me the code PrimesPalindromes.groovy, Composition.groovy, Memoize.groovy, FactorialTrampoline.groovy
  • 17. Tail Recursion • https://github.com/jlink/tailrec ©ASERT2006-2013 @TailRecursive def factorial(n, acc = 1) { n <= 1 ? acc : factorial(n - 1, n * acc) } println factorial(1000G)
  • 18. Topics • Intro to Functional Style • Functional Basics Immutability & Persistent Data Structures • Laziness & Strictness • GPars & Concurrency • Type Safety • Word Split (bonus material) • More Info ©ASERT2006-2013
  • 19. Immutability • An object’s value doesn’t change once created • Examples – Groovy has primitives & their wrapper classes, Strings, null – “constants” (final reference fields) • With some caveats about what they point to – Basic enum values • With some caveats on complex enums – Numerous (effectively) immutable classes • java.awt.Color, java.net.URI, java.util.UUID, java.lang.Class, java.util.Date, java.math.BigInteger, java.math.BigDecimal – Your own carefully written classes – Very careful use of aggregation/collection classes – Special immutable aggregation/collection classes
  • 20. Why Immutability? • Simple – Exactly one state – Potentially easier to design, implement, use, reason about & make secure • Inherently referentially transparent – Potential for optimisation • Can be shared freely – Including “constant” aggregations of immutables – Including persistent structures of immutables – Suitable for caching – Can even cache “pure” expressions involving immutables, e.g. 3 + 4, “string”.size(), fib(42) – Inherently thread safe
  • 21. Approaches to managing collection storage • Mutable • Persistent ©ASERT2006-2013 • Immutable ‘c’ ‘a’ ‘c’ ‘a’ Add ‘t’ Add ‘t’ Add ‘t’ ‘c’ ‘a’ ‘t’ ‘c’ ‘a’ ‘c’ ‘a’ ‘t’ X ‘c’ ‘a’ ‘t’ ‘c’ ‘a’
  • 22. Approaches to managing collection storage • Mutable • Persistent ©ASERT2006-2013 • Immutable ‘c’ ‘a’ ‘c’ ‘a’ Add ‘t’ Add ‘t’ Add ‘t’ ‘c’ ‘a’ ‘t’ ‘c’ ‘a’ ‘c’ ‘a’ ‘t’ X ‘c’ ‘a’ ‘t’ ‘c’ ‘a’
  • 23. Immutable practices • Using mutating style String invention = 'Mouse Trap' List inventions = [invention] invention = 'Better ' + invention inventions << invention assert inventions == ['Mouse Trap', 'Better Mouse Trap'] inventions.removeAll 'Mouse Trap' assert inventions == ['Better Mouse Trap']
  • 24. Immutable practices • Using mutating style – We could possibly get away with this code here but it has some debatable code smells • (1) add a reference to a mutable list • (2) change string reference losing original • (3),(4) mutate list • (4) duplicate first invention because original lost String invention = 'Mouse Trap' List inventions = [invention] //(1) invention = 'Better ' + invention //(2) inventions << invention //(3) assert inventions == ['Mouse Trap', 'Better Mouse Trap'] inventions.removeAll 'Mouse Trap' //(4) assert inventions == ['Better Mouse Trap']
  • 25. Approaches to managing collection storage • Mutable • Persistent ©ASERT2006-2013 • Immutable ‘c’ ‘a’ ‘c’ ‘a’ Add ‘t’ Add ‘t’ Add ‘t’ ‘c’ ‘a’ ‘t’ ‘c’ ‘a’ ‘c’ ‘a’ ‘t’ X ‘c’ ‘a’ ‘t’ ‘c’ ‘a’
  • 26. Immutable practices • Avoid using mutator methods Avoid Prefer list.sort() list.sort(false) list.unique() list.unique(false) list.reverse(true) list.reverse() list.addAll list.plus list.removeAll list.minus String or List += or << use differently named variables mutating java.util.Collections void methods, e.g. shuffle, swap, fill, copy, rotate your own non mutating variants
  • 27. Immutable practices • Avoid using mutator methods Avoid Prefer list.sort() list.sort(false) list.unique() list.unique(false) list.reverse(true) list.reverse() list.addAll list.plus list.removeAll list.minus String or List += or << use differently named variables mutating java.util.Collections void methods, e.g. shuffle, swap, fill, copy, rotate your own non mutating variants public class Collections { public static void shuffle(List<?> list) { /* ... */ } /* ... */ }
  • 28. Immutable practices • Avoid using mutator methods Avoid Prefer list.sort() list.sort(false) list.unique() list.unique(false) list.reverse(true) list.reverse() list.addAll list.plus list.removeAll list.minus String or List += or << use differently named variables mutating java.util.Collections void methods, e.g. shuffle, swap, fill, copy, rotate your own non mutating variants static List myShuffle(List list) { List result = new ArrayList(list) Collections.shuffle(result) result }
  • 29. Immutable practices • Avoid using mutator methods – But only marginal gains when using Java’s built-in collections // Avoid String invention = 'Mouse Trap' List inventions = [invention] invention = 'Better ' + invention inventions << invention assert inventions == ['Mouse Trap', 'Better Mouse Trap'] inventions.removeAll 'Mouse Trap' assert inventions == ['Better Mouse Trap'] // Prefer String firstInvention = 'Mouse Trap' List initialInventions = [firstInvention] String secondInvention = 'Better ' + firstInvention List allInventions = initialInventions + secondInvention assert allInventions == ['Mouse Trap', 'Better Mouse Trap'] List bestInventions = allInventions - firstInvention assert bestInventions == ['Better Mouse Trap']
  • 30. Immutability options - collections • Built-in • Google Collections – Numerous improved immutable collection types • Groovy run-time metaprogramming import com.google.common.collect.* List<String> animals = ImmutableList.of("cat", "dog", "horse") animals << 'fish' // => java.lang.UnsupportedOperationException def animals = ['cat', 'dog', 'horse'].asImmutable() animals << 'fish' // => java.lang.UnsupportedOperationException def animals = ['cat', 'dog', 'horse'] ArrayList.metaClass.leftShift = { throw new UnsupportedOperationException() } animals << 'fish' // => java.lang.UnsupportedOperationException
  • 31. Approaches to managing collection storage • Mutable • Persistent ©ASERT2006-2013 • Immutable ‘c’ ‘a’ ‘c’ ‘a’ Add ‘t’ Add ‘t’ Add ‘t’ ‘c’ ‘a’ ‘t’ ‘c’ ‘a’ ‘c’ ‘a’ ‘t’ X ‘c’ ‘a’ ‘t’ ‘c’ ‘a’
  • 32. Immutability – persistent collections • Functional Java – Or Functional Groovy, clj-ds, pcollections, totallylazy @Grab('org.functionaljava:functionaljava:3.1') def pets = fj.data.List.list("cat", "dog", "horse") // buy a fish def newPets = pets.cons("fish") assert [3, 4] == [pets.length(), newPets.length()] pets newPets head tail head tail head tail head tail fish cat dog horse
  • 33. Immutability – persistent collections • Functional Java @Grab('org.functionaljava:functionaljava:3.1') def pets = fj.data.List.list("cat", "dog", "horse") def newPets = pets.cons("fish") assert [3, 4] == [pets.length(), newPets.length()] // sell the horse def remaining = newPets.removeAll{ it == 'horse' } pets newPets head tail head tailhead tail head tail fish cat dog horse remaining ???
  • 34. Immutability – persistent collections • Functional Java @Grab('org.functionaljava:functionaljava:3.1') def pets = fj.data.List.list("cat", "dog", "horse") def newPets = pets.cons("fish") assert [3, 4] == [pets.length(), newPets.length()] def remaining = newPets.removeAll{ it == 'horse' } assert [3, 4, 3] == [pets, newPets, remaining]*.length() pets newPets head tail head tailhead tail head tail fish cat dog horse remaining ???
  • 35. Immutability – persistent collections • Functional Java @Grab('org.functionaljava:functionaljava:3.1') def pets = fj.data.List.list("cat", "dog", "horse") def newPets = pets.cons("fish") assert [3, 4] == [pets.length(), newPets.length()] def remaining = newPets.removeAll{ it == 'horse' } assert [3, 4, 3] == [pets, newPets, remaining]*.length() pets newPets head tail head tailhead tail head tail fish cat dog horse remaining head tail head tail head tail fish cat dog copy copy copy
  • 36. Immutability – persistent collections A B C D E F G H I K ??? J original
  • 37. Immutability – persistent collections • You will see the correct results but in general, different operations may give very differing performance characteristics from what you expect – But don’t fret, smart people are working on smart structures to support a variety of scenarios. You may even have several in your current NoSQL implementation A B C D E F G H I A* C* G* KJ original modified
  • 38. Reality check • OK, do I have to write this myself? – Might pay to try some simple ones. Take a look at Eric Lippert’s blog on some C# implementations. Here is the first part (Part 1: Kinds of Immutability): http://blogs.msdn.com/ericlippert/archive/2007/11/13/ immutability-in-c-part-one-kinds-of-immutability.aspx – Also consider • Part 2: Simple Immutable Stack, Part 3: Covariant Immutable Stack, Part 4: Immutable Queue, Part 6: Simple Binary Tree – There are probably plenty of implementations you can already use – See also: Purely Functional Data Structures by Chris Okasak, Cambridge University Press (1999) • It turns out you use trees for nearly everything! 
  • 39. Reality check • Functional Java persistent data structures – Singly-linked list (fj.data.List) – Lazy singly-linked list (fj.data.Stream) – Nonempty list (fj.data.NonEmptyList) – Optional value (a container of length 0 or 1) (fj.data.Option) – Immutable set using a red/black tree (fj.data.Set) – Immutable multi-way tree (a.k.a. rose tree) (fj.data.Tree) – Immutable tree-map using a red/black tree (fj.data.TreeMap) – Products (tuples) of arity 1-8 (fj.P1..P8) – Vectors of arity 2-8 (fj.data.vector.V2..V8) – Pointed lists and trees (fj.data.Zipper and fj.data.TreeZipper) – Type-safe, generic heterogeneous list (fj.data.hlist.HList) – Immutable arrays (fj.data.Array) – Disjoint union datatype (fj.data.Either) – 2-3 finger trees supporting access to the ends in amortized O(1) time (fj.data.fingertrees)
  • 40. Reality check • OK, have we achieved something simpler? – It depends. Understanding the insides of persistent data structures can be very hard • But as you move towards more complex systems and more concurrent systems, not having to worry about which threads are mutating what and when usually outweighs the complexities of using persistent data structures • Arguing for impure in Haskell: http://www.cse.unsw.edu.au/~benl/papers/thesis/lippmeier- impure-world.pdf – They still don’t solve all of the problems. For any significant problem you will have multiple threads working on the solution. In some sense we have just moved the problem but at least we have separated concerns. • You might combine with message passing (actors) or dataflow or software transactional memory (STM)
  • 41. Immutable Classes • Some Rules – Don’t provide mutators – Ensure that no methods can be overridden • Easiest to make the class final • Or use static factories & non-public constructors – Make all fields final – Make all fields private • Avoid even public immutable constants – Ensure exclusive access to any mutable components • Don’t leak internal references • Defensive copying in and out – Optionally provide equals and hashCode methods – Optionally provide toString method
  • 42. @Immutable... • Java Immutable Class – As per Joshua Bloch Effective Java ©ASERT2006-2013 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 + ")"; } }
  • 43. ...@Immutable... • Java Immutable Class – As per Joshua Bloch Effective Java ©ASERT2006-2013 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
  • 45. Topics • Intro to Functional Style • Functional Basics • Immutability & Persistent Data Structures Laziness & Strictness • GPars & Concurrency • Type Safety • Word Split (bonus material) • More Info ©ASERT2006-2013
  • 46. totallylazy library • Similar to Groovy’s collection GDK methods … • Except … lazy … @GrabResolver('http://repo.bodar.com/') @Grab('com.googlecode.totallylazy:totallylazy:1113') import static com.googlecode.totallylazy.Sequences.map import static com.googlecode.totallylazy.numbers.Numbers.* assert range(6, 10) == [6,7,8,9,10] assert range(6, 10, 2).forAll(even) assert range(6, 10).reduce{ a, b -> a + b } == 40 assert range(6, 10).foldLeft(0, add) == 40 assert map(range(6, 10), { it + 100 }) == [106,107,108,109,110] assert primes().take(10) == [2,3,5,7,11,13,17,19,23,29] assert range(1, 4).cycle().drop(2).take(8) == [3,4,1,2,3,4,1,2] println range(6, 1_000_000_000_000).filter(even).drop(1).take(5) // => 8,10,12,14,16 (a handful of millis later)
  • 47. Immutability options - collections • This script • Produces this output (order will vary) @GrabResolver('http://repo.bodar.com/') @Grab('com.googlecode.totallylazy:totallylazy:1113') import static com.googlecode.totallylazy.Sequences.flatMapConcurrently import static com.googlecode.totallylazy.numbers.Numbers.* println flatMapConcurrently(range(6, 10)) { println it // just for logging even(it) ? [it, it+100] : [] } //9 //7 //8 //6 //10 //6,106,8,108,10,110
  • 48. GPars and TotallyLazy library ©ASERT2006-2013 @GrabResolver('http://repo.bodar.com') @Grab('com.googlecode.totallylazy:totallylazy:1113') import static groovyx.gpars.GParsExecutorsPool.withPool import static com.googlecode.totallylazy.Callables.asString import static com.googlecode.totallylazy.Sequences.sequence withPool { pool -> assert ['5', '6'] == sequence(4, 5, 6) .drop(1) .mapConcurrently(asString(), pool) .toList() } withPool { assert ['5', '6'] == [4, 5, 6] .drop(1) .collectParallel{ it.toString() } } <= Plain GPars equivalent
  • 49. Groovy Streams • https://github.com/timyates/groovy-stream @Grab('com.bloidonia:groovy-stream:0.5.2') import groovy.stream.Stream // Repeat an object indefinitely Stream s = Stream.from { 1 } assert s.take( 5 ).collect() == [ 1, 1, 1, 1, 1 ] // Use an Iterable s = Stream.from 1..3 assert s.collect() == [ 1, 2, 3 ] // Use an iterator def iter = [ 1, 2, 3 ].iterator() s = Stream.from iter assert s.collect() == [ 1, 2, 3 ] // Use a map of iterables s = Stream.from x:1..2, y:3..4 assert s.collect() == [ [x:1,y:3],[x:1,y:4],[x:2,y:3],[x:2,y:4] ]
  • 50. Groovy Streams • https://github.com/dsrkoc/monadologie import static hr.helix.monadologie.MonadComprehension.foreach def res = foreach { a = takeFrom { [1, 2, 3] } b = takeFrom { [4, 5] } yield { a + b } } assert res == [5, 6, 6, 7, 7, 8]
  • 51. Functional Groovy • https://github.com/mperry/functionalgroovy @GrabResolver('https://oss.sonatype.org/content/groups/public') @Grab('com.github.mperry:functionalgroovy-core:0.2-SNAPSHOT') @Grab('org.functionaljava:functionaljava:3.1') import static com.github.mperry.fg.Comprehension.foreach 1.to(5).each { println it } def result = foreach { num { 1.to(2) } yield { num + 1 } } assert result.toJList() == [2, 3]
  • 52. Show me the code LazyMain.groovy
  • 53. Topics • Intro to Functional Style • Functional Basics • Immutability & Persistent Data Structures • Laziness & Strictness GPars & Concurrency • Type Safety • Word Split (bonus material) • More Info ©ASERT2006-2013
  • 54. Ralph Johnson: Parallel Programming • Styles of parallel programming – Threads and locks • Nondeterministic, low-level, rumored humans can do this – Asynchronous messages e.g. Actors – no or limited shared memory • Nondeterministic, ok for I/O but be careful with side-effects – Sharing with deterministic restrictions e.g. Fork-join • Hopefully deterministic semantics, not designed for I/O – Data parallelism • Deterministic semantics, easy, efficient, not designed for I/O ©ASERT2006-2013 http://strangeloop2010.com/talk/presentation_file/14485/Johnson-DataParallelism.pdf Each approach has some caveats
  • 55. GPars • http://gpars.codehaus.org/ • Library classes and DSL sugar providing intuitive ways for Groovy developers to handle tasks concurrently. Logical parts: – Data Parallelism features use JSR-166y Parallel Arrays to enable multi-threaded collection processing – Asynchronous functions extend the Java 1.5 built-in support for executor services to enable multi-threaded closure processing – Dataflow Concurrency supports natural shared-memory concurrency model, using single-assignment variables – Actors provide an implementation of Erlang/Scala-like actors including "remote" actors on other machines – Safe Agents provide a non-blocking mt-safe reference to mutable state; inspired by "agents" in Clojure ©ASERT2006-2013
  • 56. Coordination approachesSource:ReGinA–GroovyinAction,2ndedition Data Parallelism: Fork/Join Map/Reduce Fixed coordination (for collections) Actors Explicit coordination Safe Agents Delegated coordination Dataflow Implicit coordination
  • 57. GPars: Choosing approachesFormoredetailssee:http://gpars.codehaus.org/Concepts+compared Parallel Collections Data Parallelism Task Parallelism Streamed Data Parallelism Fork/ Join Dataflow operators CSP Actors Dataflow tasks Actors Asynch fun’s CSP Fork/ Join Immutable Stm, Agents Special collections Synchronization Linear Recursive Linear Recursive Shared Data Irregular Regular
  • 58. Groovy Sequential Collection ©ASERT2006-2013 def oneStarters = (1..30) .collect { it ** 2 } .findAll { it ==~ '1.*' } assert oneStarters == [1, 16, 100, 121, 144, 169, 196] assert oneStarters.max() == 196 assert oneStarters.sum() == 747
  • 59. GPars Parallel Collections… ©ASERT2006-2013 import static groovyx.gpars.GParsPool.withPool withPool { def oneStarters = (1..30) .collectParallel { it ** 2 } .findAllParallel { it ==~ '1.*' } assert oneStarters == [1, 16, 100, 121, 144, 169, 196] assert oneStarters.maxParallel() == 196 assert oneStarters.sumParallel() == 747 }
  • 60. …GPars Parallel Collections • Suitable when – Each iteration is independent, i.e. not: fact[index] = index * fact[index - 1] – Iteration logic doesn’t use non-thread safe code – Size and indexing of iteration are important ©ASERT2006-2013 import static groovyx.gpars.GParsPool.withPool withPool { def oneStarters = (1..30) .collectParallel { it ** 2 } .findAllParallel { it ==~ '1.*' } assert oneStarters == [1, 16, 100, 121, 144, 169, 196] assert oneStarters.maxParallel() == 196 assert oneStarters.sumParallel() == 747 }
  • 61. Parallel Collection Variations • Apply some Groovy metaprogramming ©ASERT2006-2013 import static groovyx.gpars.GParsPool.withPool withPool { def oneStarters = (1..30).makeConcurrent() .collect { it ** 2 } .findAll { it ==~ '1.*' } .findAll { it ==~ '...' } assert oneStarters == [100, 121, 144, 169, 196] } import groovyx.gpars.ParallelEnhancer def nums = 1..5 ParallelEnhancer.enhanceInstance(nums) assert [1, 4, 9, 16, 25] == nums.collectParallel{ it * it }
  • 62. GPars parallel methods for collections Transparent Transitive? Parallel Lazy? any { ... } anyParallel { ... } yes collect { ... } yes collectParallel { ... } count(filter) countParallel(filter) each { ... } eachParallel { ... } eachWithIndex { ... } eachWithIndexParallel { ... } every { ... } everyParallel { ... } yes find { ... } findParallel { ... } findAll { ... } yes findAllParallel { ... } findAny { ... } findAnyParallel { ... } fold { ... } foldParallel { ... } fold(seed) { ... } foldParallel(seed) { ... } grep(filter) yes grepParallel(filter) groupBy { ... } groupByParallel { ... } max { ... } maxParallel { ... } max() maxParallel() min { ... } minParallel { ... } min() minParallel() split { ... } yes splitParallel { ... } sum sumParallel // foldParallel + Transitive means result is automatically transparent; Lazy means fails fast FormoredetailsseeReGinAortheGParsdocumentation
  • 63. GPars: Map-Reduce ©ASERT2006-2013 import static groovyx.gpars.GParsPool.withPool withPool { def oneStarters = (1..30).parallel .map { it ** 2 } .filter { it ==~ '1.*' } assert oneStarters.collection == [1, 16, 100, 121, 144, 169, 196] // aggregations/reductions assert oneStarters.max() == 196 assert oneStarters.reduce { a, b -> a + b } == 747 assert oneStarters.sum() == 747 }
  • 64. GPars parallel array methods Method Return Type combine(initValue) { ... } Map filter { ... } Parallel array collection Collection groupBy { ... } Map map { ... } Parallel array max() T max { ... } T min() T min { ... } T reduce { ... } T reduce(seed) { ... } T size() int sort { ... } Parallel array sum() T parallel // on a Collection Parallel array FormoredetailsseeReGinAortheGParsdocumentation
  • 65. Parallel Collections vs Map-Reduce Fork Fork JoinJoin Map Map Reduce Map Map Reduce Reduce Map Filter FilterMap
  • 66. Concurrency challenge… • Suppose we have the following calculation involving several functions: • And we want to use our available cores … ©ASERT2006-2013 // example adapted from Parallel Programming with .Net 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
  • 67. …Concurrency challenge… • We can analyse the example’s task graph: ©ASERT2006-2013 // example adapted from Parallel Programming with .Net 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
  • 68. …Concurrency challenge… • Manually using asynchronous functions: ©ASERT2006-2013 // example adapted from Parallel Programming with .Net def (f1, f2, f3, f4) = [{ sleep 1000; it }] * 3 + [{ x, y -> x + y }] import static groovyx.gpars.GParsPool.withPool 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 b c d f
  • 69. …Concurrency challenge • And with GPars Dataflows: ©ASERT2006-2013 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
  • 70. …Concurrency challenge • And with GPars Dataflows: ©ASERT2006-2013 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
  • 71. GPars: Dataflows... ©ASERT2006-2013 import groovyx.gpars.dataflow.DataFlows import static groovyx.gpars.dataflow.DataFlow.task final flow = new DataFlows() task { flow.result = flow.x + flow.y } task { flow.x = 10 } task { flow.y = 5 } assert 15 == flow.result new DataFlows().with { task { result = x * y } task { x = 10 } task { y = 5 } assert 50 == result } 510 yx *
  • 72. ...GPars: Dataflows... • Evaluating: ©ASERT2006-2013 import groovyx.gpars.dataflow.DataFlows import static groovyx.gpars.dataflow.DataFlow.task final flow = new DataFlows() task { flow.a = 10 } task { flow.b = 5 } task { flow.x = flow.a - flow.b } task { flow.y = flow.a + flow.b } task { flow.result = flow.x * flow.y } assert flow.result == 75 b 10 5 a +- * result = (a – b) * (a + b) x y Question: what happens if I change the order of the task statements here?
  • 73. ...GPars: Dataflows... • Naive attempt for loops ©ASERT2006-2013 import groovyx.gpars.dataflow.Dataflows import static groovyx.gpars.dataflow.Dataflow.task final flow = new Dataflows() [10, 20].each { thisA -> [4, 5].each { thisB -> task { flow.a = thisA } task { flow.b = thisB } task { flow.x = flow.a - flow.b } task { flow.y = flow.a + flow.b } task { flow.result = flow.x * flow.y } println flow.result } } // => java.lang.IllegalStateException: A DataflowVariable can only be assigned once. ... task { flow.a = 10 } ... task { flow.a = 20 } Don’t do this! X
  • 74. ...GPars: Dataflows... ©ASERT2006-2013 import groovyx.gpars.dataflow.DataflowStream import static groovyx.gpars.dataflow.Dataflow.* final streamA = new DataflowStream() final streamB = new DataflowStream() final streamX = new DataflowStream() final streamY = new DataflowStream() final results = new DataflowStream() operator(inputs: [streamA, streamB], outputs: [streamX, streamY]) { a, b -> streamX << a - b; streamY << a + b } operator(inputs: [streamX, streamY], outputs: [results]) { x, y -> results << x * y } [[10, 20], [4, 5]].combinations().each{ thisA, thisB -> task { streamA << thisA } task { streamB << thisB } } 4.times { println results.val } b 10 10 20 20 4 5 4 5 a +- * 84 75 384 375
  • 75. ...GPars: Dataflows • Suitable when: – Your algorithms can be expressed as mutually- independent logical tasks • Properties: – Inherently safe and robust (no race conditions or livelocks) – Amenable to static analysis – Deadlocks “typically” become repeatable – “Beautiful” (declarative) code ©ASERT2006-2013 import groovyx.gpars.dataflow.Dataflows import static groovyx.gpars.dataflow.Dataflow.task final flow = new Dataflows() task { flow.x = flow.y } task { flow.y = flow.x }
  • 76. …GPars: Actors... ©ASERT2006-2013 import static groovyx.gpars.actor.Actors.* def votes = reactor { it.endsWith('y') ? "You voted for $it" : "Sorry, please try again" } println votes.sendAndWait('Groovy') println votes.sendAndWait('JRuby') println votes.sendAndWait('Go') def languages = ['Groovy', 'Dart', 'C++'] def booth = actor { languages.each{ votes << it } loop { languages.size().times { react { println it } } stop() } } booth.join(); votes.stop(); votes.join() You voted for Groovy You voted for JRuby Sorry, please try again You voted for Groovy Sorry, please try again Sorry, please try again
  • 77. Software Transactional Memory… ©ASERT2006-2013 @Grab('org.multiverse:multiverse-beta:0.7-RC-1') import org.multiverse.api.references.LongRef import static groovyx.gpars.stm.GParsStm.atomic import static org.multiverse.api.StmUtils.newLongRef class Account { private final LongRef balance Account(long initial) { balance = newLongRef(initial) } void setBalance(long newBalance) { if (newBalance < 0) throw new RuntimeException("not enough money") balance.set newBalance } long getBalance() { balance.get() } } // ...
  • 78. …Software Transactional Memory ©ASERT2006-2013 // ... def from = new Account(20) def to = new Account(20) def amount = 10 def watcher = Thread.start { 15.times { atomic { println "from: ${from.balance}, to: ${to.balance}" } sleep 100 } } sleep 150 try { atomic { from.balance -= amount to.balance += amount sleep 500 } println 'transfer success' } catch(all) { println all.message } atomic { println "from: $from.balance, to: $to.balance" } watcher.join()
  • 79. Topics • Intro to Functional Style • Functional Basics • Immutability & Persistent Data Structures • Laziness & Strictness • GPars & Concurrency Type Safety • Word Split (bonus material) • More Info ©ASERT2006-2013
  • 80. Show me the code JScience, SPrintfChecker, GenericStackTest
  • 81. Topics • Intro to Functional Style • Functional Basics • Immutability & Persistent Data Structures • Laziness & Strictness • GPars & Concurrency • Type Safety Word Split (bonus material) • More Info ©ASERT2006-2013
  • 82. Word Split with Fortress ©ASERT2006-2013 Guy Steele’s StrangeLoop keynote (from slide 52 onwards for several slides): http://strangeloop2010.com/talk/presentation_file/14299/GuySteele-parallel.pdf
  • 83. Word Split… ©ASERT2006-2013 def swords = { s -> def result = [] def word = '' s.each{ ch -> if (ch == ' ') { if (word) result += word word = '' } else word += ch } if (word) result += word result } assert swords("This is a sample") == ['This', 'is', 'a', 'sample'] assert swords("Here is a sesquipedalian string of words") == ['Here', 'is', 'a', 'sesquipedalian', 'string', 'of', 'words']
  • 84. Word Split… ©ASERT2006-2013 def swords = { s -> def result = [] def word = '' s.each{ ch -> if (ch == ' ') { if (word) result += word word = '' } else word += ch } if (word) result += word result }
  • 85. Word Split… ©ASERT2006-2013 def swords = { s -> def result = [] def word = '' s.each{ ch -> if (ch == ' ') { if (word) result += word word = '' } else word += ch } if (word) result += word result }
  • 88. Segment(left1, m1, right1) Segment(left2, m2, right2) Segment(left1, m1 + [ ? ] + m2, right2) …Word Split… ©ASERT2006-2013
  • 89. …Word Split… ©ASERT2006-2013 class Util { static maybeWord(s) { s ? [s] : [] } } import static Util.* @Immutable class Chunk { String s public static final ZERO = new Chunk('') def plus(Chunk other) { new Chunk(s + other.s) } def plus(Segment other) { new Segment(s + other.l, other.m, other.r) } def flatten() { maybeWord(s) } } @Immutable class Segment { String l; List m; String r public static final ZERO = new Segment('', [], '') def plus(Chunk other) { new Segment(l, m, r + other.s) } def plus(Segment other) { new Segment(l, m + maybeWord(r + other.l) + other.m, other.r) } def flatten() { maybeWord(l) + m + maybeWord(r) } }
  • 90. …Word Split… ©ASERT2006-2013 def processChar(ch) { ch == ' ' ? new Segment('', [], '') : new Chunk(ch) } def swords(s) { s.inject(Chunk.ZERO) { result, ch -> result + processChar(ch) } } assert swords("Here is a sesquipedalian string of words").flatten() == ['Here', 'is', 'a', 'sesquipedalian', 'string', 'of', 'words']
  • 93. …Word Split… ©ASERT2006-2013 THREADS = 4 def pwords(s) { int n = (s.size() + THREADS - 1) / THREADS def map = new ConcurrentHashMap() (0..<THREADS).collect { i -> Thread.start { def (min, max) = [ [s.size(), i * n].min(), [s.size(), (i + 1) * n].min() ] map[i] = swords(s[min..<max]) } }*.join() (0..<THREADS).collect { i -> map[i] }.sum().flatten() }
  • 94. …Word Split… ©ASERT2006-2013 import static groovyx.gpars.GParsPool.withPool THRESHHOLD = 10 def partition(piece) { piece.size() <= THRESHHOLD ? piece : [piece[0..<THRESHHOLD]] + partition(piece.substring(THRESHHOLD)) } def pwords = { input -> withPool(THREADS) { partition(input).parallel.map(swords).reduce{ a, b -> a + b }.flatten() } }
  • 95. …Guy Steele example in Groovy… ©ASERT2006-2013 def words = { s -> int n = (s.size() + THREADS - 1) / THREADS def min = (0..<THREADS).collectEntries{ [it, [s.size(),it*n].min()] } def max = (0..<THREADS).collectEntries{ [it, [s.size(),(it+1)*n].min()] } def result = new DataFlows().with { task { a = swords(s[min[0]..<max[0]]) } task { b = swords(s[min[1]..<max[1]]) } task { c = swords(s[min[2]..<max[2]]) } task { d = swords(s[min[3]..<max[3]]) } task { sum1 = a + b } task { sum2 = c + d } task { sum = sum1 + sum2 } println 'Tasks ahoy!' sum } switch(result) { case Chunk: return maybeWord(result.s) case Segment: return result.with{ maybeWord(l) + m + maybeWord(r) } } } DataFlow version: partially hard-coded to 4 partitions for easier reading
  • 96. …Guy Steele example in Groovy… ©ASERT2006-2013 GRANULARITY_THRESHHOLD = 10 THREADS = 4 println GParsPool.withPool(THREADS) { def result = runForkJoin(0, input.size(), input){ first, last, s -> def size = last - first if (size <= GRANULARITY_THRESHHOLD) { swords(s[first..<last]) } else { // divide and conquer def mid = first + ((last - first) >> 1) forkOffChild(first, mid, s) forkOffChild(mid, last, s) childrenResults.sum() } } switch(result) { case Chunk: return maybeWord(result.s) case Segment: return result.with{ maybeWord(l) + m + maybeWord(r) } } } Fork/Join version
  • 97. …Guy Steele example in Groovy ©ASERT2006-2013 println GParsPool.withPool(THREADS) { def ans = input.collectParallel{ processChar(it) }.sum() switch(ans) { case Chunk: return maybeWord(ans.s) case Segment: return ans.with{ maybeWord(l) + m + maybeWord(r) } } } Just leveraging the algorithm’s parallel nature
  • 98. Topics • Intro to Functional Style • Functional Basics • Immutability & Persistent Data Structures • Laziness & Strictness • GPars & Concurrency • Type Safety • Word Split (bonus material) More Info ©ASERT2006-2013