SlideShare ist ein Scribd-Unternehmen logo
1 von 84
Downloaden Sie, um offline zu lesen
Grooming With Groovy
Come,Code Along!
dhaval.dalal@software-artisan.com
@softwareartisan
Hello World…
Concise - convey more in less
Groovy Classes Are Java Classes
Everything is an object.
Flexibility
Dynamic Language
Program extension at runtime by altering
behaviour and structure of objects/types -
“Open Classes”
Code synthesis
Add code at runtime
As opposed to manipulating byte code in Static
Languages like Java.
Groovy’s extension to JDK is called GDK
Uncertainty
Pimp(extend) my Library
Extending the class - additive operation.
Monkey Patching
Redefining things again - Don’t cause
fires!
Break glass in case of fire - reach out
for this meta-programming hammer only
then.
Adding != Redefining
Typing 101
Type?
How do I interpret data in that block of
memory and what operations can I perform
on it?
Safety?
Any attempt to misinterpret data is
caught at compile time OR generates a
well-specified error at runtime.
Dynamic & Static Typing
Statically Typed Language
Type of every expression can be
determined by static program analysis
(before it runs).
Compile-time type checking.
Align types naturally or by casting.
Dynamically Typed
Runtime type checking, not compile-time
checking
Dynamic Typing
Infers Type based on context.
Numbers and Decimals
We rely on static typing for code
safety, but it still can fail us.
Generics
ArrayStoreException
Dynamic & Static Typing
Optional & Duck Typing
Optionally Typed
Specify when you need, and leave it to Groovy
to figure it out where you don’t care.
Duck Typing
Don’t need a type to invoke a method on
object. If its there, you can invoke it
Objects behave as demanded of them in a given
context, rather than ensuring that they are
of a specific type.
You can treat it like a dog or even god.
Ram (Static) Balram (Dynamic)
Static typing catches bugs with
the compiler and keeps you out
of trouble.
Static typing only catches some bugs,
and you can’t trust the compiler to
do your testing
Static languages are easier to
read because they’re more
explicit about what the code
does.
Dynamic languages are easier to read
because you write less code.
At least I know that the code
compiles.
Just because the code compiles
doesn’t mean it runs.
I trust the static typing to
make sure my team writes good
code.
The compiler doesn’t stop you from
writing bad code.
Debugging an unknown object is
impossible.
Debugging overly complex object
hierarchies is unbearable.
Compiler bugs happen at
midmorning in my office; runtime
bugs happen at midnight for my
customers.
There’s no replacement for testing,
and unit tests find more issues than
the compiler ever could.
Source: http://www.smashingmagazine.com/2013/04/18/introduction-to-programming-type-systems/
Use correct typing to solve the problem
at hand
Doesn’t matter if you have to use more than
one at a given time.
Use Static typing where possible,
Dynamic typing when needed - Eric Meijer
Avoid Polarization
Like a good manager, play on strengths of
each :-)
Dynamic or Static
Typing?
Weakly Typed
The type of a value depends on how it
is used.
Can mix operations between mismatched
types without explicit conversion
C lets you define object types as
structures, but it doesn’t do much to
enforce or remember them. C automatically
converts between many types.
http://c2.com/cgi/wiki?WeakAndStrongTyping
Strongly Typed Language
A Language in which all expressions are type
consistent is Strongly Typed.
A value has a type and that type cannot change.
What you can do to a value depends on the type of
the value.
Can’t mix operations between mismatched types, if
you do, the runtime catches you. You must convert
explicitly.
But, being liberal with type conversions doesn't
really mean the same as saying that the language
is weakly typed!
http://c2.com/cgi/wiki?WeakAndStrongTyping
Weakly
Typed
Strongly
Typed
Statically
Typed
C/C++
Haskell/Java/
C#
Dynamically
Typed
JavaScript/
Perl
Groovy/Ruby/
Python
Source: http://c2.com/cgi/wiki?TypingQuadrant
The Typing Quadrant
Strings in Groovy
Literal Strings
String Interpolation
GString - Nah, stop fantasising!
Allow in-place evaluation of expressions…and
for that you have to use the $ ;-)
Multi-line String
Lazy Evaluation
Slashy Strings
Match found!
Pattern from String
use operator ~
Determine a match =~
For exact match ==~
Regex Readability
Prefer Slashy strings over normal ones
Truth & Difficult
Situations
Groovy Truth
Dealing with Exceptions
No force to catch Java’s Checked Exceptions
Dealing with Absent Values
null is an object, try null.getClass() and
toString()
null-safe operator (?.)
Methods and
Parameters
Properties (Getters and Setters)
Trailing Optional Parameters
Positional parameters -
@TupleConstructor
@Cannonical = @EqualsAndHashCode,
@ToString and @TupleConstructor
Hello Operator!
Preserve semantics when using Operator
overloading.
When someone asks you - what does this
operator do? You know the answer :-)
Use it to harmonise with the domain/
context
Typically very nice for value objects.
Multi-Methods
Also called as Multiple Dispatch.
Dispatch based on type of the receiver.
Example, Java/C#/Scala
and based on Run-time Type of the arguments,
not on Compile-time type (as in Java).
Example, Clojure
The equals method.
A Peek at GDK
Producing and Consuming XML
Spawning Processes
Using Files
Using Configuration
Avoid properties hell.
Using SQL
Compose behaviours,
Don’t inherit
@Delegate
@Mixin (< 2.3)
Traits (>= 2.3, @Mixin deprecated)
trait -> Language keyword, not an AST
transformation
Traits
Like interfaces, they cannot be
instantiated.
However, unlike interfaces, they can have
implementation and state.
Can contain abstract methods.
Classes can inherit multiple traits or
implement at run-time.
Trait can extend another trait and
implement interfaces as well.
Methods are “real” and visible from Java as
well.
Closures
Objects = data + behavior, whereas
Closures = behavior.
Convert Methods to Closures.
Using the object.&method
Static, Instance or in Script methods.
The with closure.
Closures in Action
AOP around style using Closures.
Loan My Resource - like try-with-
resources in Java.
Closure as an interface.
Query Closure to find
maximumNumberOfParameters
parameterTypes
and alter the response accordingly -
polymorphic closures.
More on Closures
Memoized Closures and @Memoized
methods
Remember me and I’ll help you!
Trampolined Closures and
@TailRecursive methods
Don’t jump that high, but instead jump
many times!
More on Closures
Curried Closures
Spice that helps us re-shape and re-
purpose!
curry, rcurry
Composing Closures
The way to tackle complexity!
>> and <<
When to use Closures?
Eliminating Dependencies
Esp. on single method interfaces
Building Declarative APIs and
Preserving encapsulation.
External iterators or getters expose innards
of an aggregate, instead use internal
iterators and call closure.
Building DSLs
Using HOFs it becomes easy to construct DSLs
Lazy Evaluation
Hello Collections…
Lists - [] , Maps - [:], Ranges -
(a..b), Sets
Tuples
Iterate each element.
each, reverseEach, eachWithIndex
Transform each element.
collect, collectNested, collectMany and
collectEntries
Collection Operations
Retrieve Elements that satisfy certain
criterion
find, findAll
Transform using predicate (collect +
~find)
findResult(s)
Combine adjacent elements
sum, inject, min, max
Collection Ops
Queries
contains, count, any, every
Mutating Operations
reverse, removeAll, retainAll
Generators
collate, permutations, combinations,
subsequences, transpose
Collection Ops
Set-Style Operations
intersect, disjoint, plus (union)
Distinct and Order By
unique, sort
Partition Collection to Map
groupBy, groupEntriesBy, countBy
split and join
drop, take, dropWhile, takeWhile
Spreading Collections
The Spread-dot Operator (*.)
Array and List as varargs
The Spread Operator (*)
Map as an Interface.
Very useful when Stubbing
FP in Groovy
Like in other languages Java/C#/Ruby
etc…, in-place mutation is a standing
invitation in Groovy too!
Its hard to avoid falling into that trap.
One has to work hard to bring immutability.
A change to Immutable Object produces
another Immutable Object
Promotes caching of objects - Flyweights.
Promotes concurrent operations.
FP in Groovy
Use Expressions wherever possible
Statements effect change by mutation thus
encourage mutability
Expressions evaluate and return value thus
encourage immutability
Use Pure Functions wherever possible
Order of program evaluation
Referential Transparency
Memoization
Immutability
Immutability and Pure functions make
it easier to reason about programs
Use @Immutable to make a class
immutable
Immutability
Collection
APIs
Prefer
Immutable
version
Over
Mutable
version
Adding + <<, addAll
Removing - removeAll
Sorting sort(false) sort()
Reversing reverse() reverse(false)
Lazy Evaluation
Lazy Evaluation (by-name)
Don’t compute until actually required.
Lazy Evaluation (by-need)
Store the result of computation for
future use and avoid re-computation
@Lazy AST Transformation
Needs to be initialised at the time of
declaration
Being Lazy is efficient
Lazy defaults on Lists
Lazy Sequences
A sequence whose tail is evaluated
only someone wants to know its
value.
Materialise on demand to avoid
unnecessary computation of tail.
Lets implement
Immutable Stream
Stream implementation shown in these slides is available on:
https://github.com/CodeJugalbandi/FunctionalProgramming/blob/master/melodies/lazy_sequences/Stream.groovy
Lets implement
Immutable Stream
How can we implement
a lazy List in
Groovy?
1 ?
Stream implementation shown in these slides is available on:
https://github.com/CodeJugalbandi/FunctionalProgramming/blob/master/melodies/lazy_sequences/Stream.groovy
Lets implement
Immutable Stream
How can we implement
a lazy List in
Groovy?
By using closure on the
tail of the list.
Additionally for
performance - use
Memoization on that
closure.
Evaluate
tail
1 ?
1 *
2 ?
Stream implementation shown in these slides is available on:
https://github.com/CodeJugalbandi/FunctionalProgramming/blob/master/melodies/lazy_sequences/Stream.groovy
Ingredients for Lazy
Evaluation
Groovy uses eager evaluation for
method arguments.
Args are evaluated before passing to the
method.
To delay the evaluation of method
arguments (lazy), wrap them in Closure
Invoke the closure explicitly in the method
when we need the evaluation result.
Ingredients for Lazy
Evaluation
Wrap in
Closure for
Lazy Calls
for storing result of
evaluation and avoiding
computation again,
performance optimisation
CAVEAT:
Only for
pure
functions!
Evaluation
on Closure
Call
Stream
with head
and
lazy
evaluated
tail
As Streams are
immutable we can
structurally share the
earlier stream.
Stream(T head, Stream<T> tail) {
_head = head
_tail = {-> tail}.memoize()
}
new Stream<Integer>(1, new Stream(null, null))
Stream(T head, Closure tail) {
_head = head
_tail = tail.memoize()
}
new Stream<Integer>(1, {-> new Stream(null, {-> null})})
Causes Immediate
Evaluation - Eager
Hence wrap the tail
stream in a Closure at
the time of Stream
Creation - Lazy
Introduce Empty Stream
Define toString
String toString() {
if (isEmpty()) ‘[]’ else “[${head()}, ?]”
}
} // End of Stream class
def empty = Stream.Empty
println empty // []
def singleton = new Stream(1, {-> empty})
println singleton // [1, ?]
def couple = new Stream(2, {-> singleton})
println couple // [2, ?]
def leftShift(T element) {
new Stream(element, {-> this})
}
} // End of Stream class
def stream = Stream.Empty << 1 << 2
println stream // [2, ?]
println stream.head() // 2
println stream.tail() // [1, ?]
println stream.tail().tail() // []
Consing to Stream
Prepend (Cons)
Construct a Stream
from few elements
static def of(T ...ts) {
def stream = Stream.Empty
ts.reverseEach {
stream = stream << it
}
stream
}
} // End of Stream class
def stream = Stream.of(1, 2, 3, 4)
println stream // [1, ?]
Construct a Stream
from Range
static def range(Range range, Integer step) {
Stream.of(*range.step(step))
}
} // End of Stream class
println Stream.range('a'..'z')
println Stream.range(‘A'..'Z', 2)
println Stream.range(-10..5)
println Stream.range(new Date("12-Dec-2012")..new
Date("19-Jan-2013"))
Force entire Stream
to Evaluate
def force() {
if (isEmpty()) []
else [head()] + tail().force()
}
} // End of Stream class
def empty = Stream.Empty
println empty // []
def stream = Stream.of(1, 2, 3, 4)
println stream.force() // [1, 2, 3, 4]
Drop first few and
take the rest
def drop(howMany) {
if (isEmpty() || howMany <= 0) this
else tail().drop(howMany - 1)
}
} // End of Stream class
def empty = Stream.Empty
println empty.drop(2).force() // []
def stream = Stream.of(1, 2, 3, 4)
println stream.drop(2) // [3, ?]
println stream.drop(2).force() // [3, 4]
println stream.drop(9).force() // []
stream as a function
of its index
def call(index) {
def list = take(index + 1).force()
if (index > list.size() - 1)
throw new Exception(“Index $index out of bounds”)
list[index]
}
} // End of Stream class
def empty = Stream.Empty
println empty(2) // Exception: Index 2 out of bounds
def stream = Stream.of(1, 2, 3, 4)
println stream(0) // 1
println stream(3) // 4
println stream(4) // Exception: Index 4 out of bounds
Combining Adjacent
Elements Using fold
def fold(acc, Closure fn) {
if (isEmpty()) acc
else tail().fold(fn(acc, head()), fn)
}
} // End of Stream class
def stream = Stream.of(1, 2, 3, 4)
// Sum of all elements
println stream.fold(0) { acc, elem -> acc + elem } // 10
// Product of all elements
println stream.fold(1) { acc, elem -> acc * elem } // 24
TailRecursive fold
@TailRecursive
def fold(stream = this, acc, Closure fn) {
if (stream.isEmpty()) acc
else fold(stream.tail(), fn(acc, stream.head()), fn)
}
} // End of Stream class
def stream = Stream.of(1, 2, 3, 4)
// Sum of all elements
println stream.fold(0) { acc, elem -> acc + elem } // 10
// Product of all elements
println stream.fold(1) { acc, elem -> acc * elem } // 24
Express force
in terms of fold
But why do we do this?
def force() {
fold([]) { acc, elem -> acc + elem }
}
} // End of Stream class
def empty = Stream.Empty
println empty // []
def stream = empty << 1 << 2 << 3 << 4
println stream.force() // [4, 3, 2, 1]
force() [4, ?]
[4] + force() [3, ?]
[4] + [3] + force() [2, ?]
[4] + [3] + [2] + force() [1, ?]
[4] + [3] + [2] + [1] + force() []
[4] + [3] + [2] + ([1] + [])
[4] + [3] + ([2] + [1])
[4] + ([3] + [2, 1])
[4] + [3, 2, 1]
[4, 3, 2, 1]
fold [4, ?] []
fold [3, ?] [4]
fold [2, ?] [4, 3]
fold [1, ?] [4, 3, 2]
fold [] [4, 3, 2, 1]
[4, 3, 2, 1]
Shape of the
process becomes
iterative after
expressing it in
terms of fold.
Earlier force
implementation was a
recursive process.
Shapes of Processes
Build-up on
stack like this
causes it to
overflow
State
passed as
parameter
State
stored on
stack
Reverse
def reverse() {
fold(Stream.Empty) { stream, elem ->
stream << elem
}
}
} // End of Stream class
def stream = Stream.of(1, 2, 3, 4)
println stream.reverse() // [4, ?]
println stream.reverse().force() // [4, 3, 2, 1]
TailRecursive foldN
@TailRecursive
def foldN(stream = this, howMany, acc, Closure fn) {
if (stream.isEmpty() || howMany <= 0) acc
else foldN(stream.tail(), howMany - 1, fn(acc, stream.head()), fn)
}
} // End of Stream class
def stream = Stream.of(1, 2, 3, 4)
// Sum of 2 elements
println stream.foldN(2, 0) { acc, elem -> acc + elem } // 3
// Product of 2 elements
println stream.foldN(2, 1) { acc, elem -> acc * elem } // 2
Express drop
in terms of foldN
def drop(howMany) {
foldN(howMany, this) { stream, elem -> stream.tail() }
}
} // End of Stream class
def empty = Stream.Empty
println empty.drop(2).force() // []
def stream = Stream.of(1, 2, 3, 4)
println stream.drop(2) // [3, ?]
println stream.drop(2).force() // [3,4]
println stream.drop(9).force() // []
Filter elements by
criteria
def filter(Closure predicate) {
if (isEmpty())
Stream.Empty
else if (predicate(head()))
new Stream(head(), {-> tail().filter(predicate)})
else
tail().filter(predicate)
}
} // End of Stream class
def stream = Stream.of(1, 2, 3, 4)
println stream.filter { it % 2 == 0 } // [2, ?]
println stream.filter { it % 2 != 0 }.force() // [1, 3]
Take while
predicate holds
def takeWhile(Closure predicate) {
if (isEmpty())
Stream.Empty
else if (predicate(head()))
new Stream(head(), {-> tail().takeWhile(predicate)})
else
Stream.Empty
}
} // End of Stream class
def empty = Stream.Empty
println empty.takeWhile { it == 1 } // []
def stream = Stream.of(1, 1, 1, 2, 1, 2)
println stream.takeWhile { it == 1 } // [1, ?]
println stream.takeWhile { it == 1 }.force() // [1, 1, 1]
Drop while
predicate holds
def dropWhile(Closure predicate) {
if (isEmpty()) Stream.Empty
else if (predicate(head())) tail().dropWhile(predicate)
else this
}
} // End of Stream class
def empty = Stream.Empty
println empty.dropWhile { it == 1 } // []
def stream = def stream = Stream.of(1, 1, 1, 2, 1, 2)
println stream.dropWhile { it == 1 } // [2, ?]
println stream.dropWhile { it == 1 }.force() // [2, 1, 2]
Transform each
Element
def map(Closure fn) {
if (isEmpty()) Stream.Empty
else new Stream(fn(head()), {-> tail().map(fn)})
}
} // End of Stream class
def stream = Stream.of(1, 2, 3, 4)
println stream.map { it * 2 } // [1, ?]
println stream.map { it * it }.force() // [1, 4, 9, 16]
Transform using
Predicate
def collect(Closure predicate) {
if (isEmpty())
Stream.Empty
else if (predicate(head()))
new Stream(predicate(head()), {-> tail().collect(predicate)})
else
tail().collect(predicate)
}
} // End of Stream class
def stream = Stream.of(1, 2, 3, 4)
def squaredEvens = stream.collect {
if (it % 2 == 0) it * it // Square Evens, leave Odds
else null // Groovy truth expression that evaluates to false
}
println squaredEvens // [4, ?]
println squaredEvens.force() // [4, 16]
Iterate each element
def forEach(Closure fn) {
if (isEmpty())
Stream.Empty
else {
fn(head())
tail().forEach(fn)
}
}
} // End of Stream class
def stream = Stream.of(1, 2, 3, 4)
stream.forEach { print it } // 1234
Non-Terminating
Recursion
static def generate(Closure fn) {
new Stream(fn(), {-> generate(fn)})
}
} // End of Stream class
def rnd = new java.util.Random()
def stream = Stream.generate { rnd.nextInt(10) }
println stream.take(5).force()
Non-Terminating
Recursion
static def iterate(initial, Closure fn) {
new Stream(initial, {-> iterate(fn(initial), fn) })
}
static def from(n) {
iterate(n) { it + 1 }
}
} // End of Stream class
Infinitely Lazy
Streams, unlike lists (eager), are
lazy.
Streams, unlike lists (finite), are
infinite.
They have a starting point, but no end.
// The below will not terminate
Stream.from(4).forEach { println it }
Finite from Infinite
Take what we are interested in and
leave the rest in ether!
def numbersFrom4 = Stream.from(4)
println numbersFrom4.take(2).force() // [4, 5]
println numbersFrom4.take(5).force() // [4, 5, 6, 7, 8]
Find first 6 primes using the Sieve of
Eratosthenes
Hint: Use Stream created earlier
http://world.mathigon.org/Prime_Numbers
Sieve
def sieve(s) {
def first = s.head()
def rest = s.tail().filter { it % first != 0 }
new Stream(first, {-> sieve(rest)})
}
def primes = sieve(Stream.from(2)).take(6)
println primes.force() // [2, 3, 5, 7, 11, 13]
Non-Memoized Tail
Serious Performance hit as tail is wrapped in
closure and if when called several times the
stream is recomputed each time upon call.
Memoized Tail
Zip two Streams
def zip(Stream<T> that) {
if (isEmpty() || that.isEmpty())
Stream.Empty
else
new Stream(new Tuple(head(), that.head()), {-> tail().zip(that.tail()) })
}
} // End of Stream class
def s1 = Stream.of(0, 1, 2)
def s2 = Stream.of(4, 5, 6)
def zipped = s1.zip(s2)
println zipped // [[0, 4], ?]
println zipped.tail() // [[1, 5], ?]
println zipped.force() // [0, 4, 1, 5, 2, 6]
println zipped.force().collate(2) // [[2, 6], [1, 5], [0,4]]
// Sum of 2 streams
println zipped.map {
def (first, second) = it
first + second
}.force() // [4, 6, 8]
Zip with Index
def zipWithIndex() {
zip(from(0))
}
} // End of Stream class
def stream = Stream.of('a', 'b', 'c', 'd')
stream.zipWithIndex().forEach {
print it // [a, 0][b, 1][c, 2][d, 3]
}
def fibonacci(s) {
def next = s.zip(s.tail()).map {
def (first, second) = it
first + second
}
def rest = s << next.head()
new Stream(s.head(), {-> fibonacci(rest)})
}
First 10 Fibonacci Nos.
https://www.haskell.org/tutorial/functions.html
def stream = Stream.from(0).take(2)
println stream.force() // [0, 1]
// Start with seed elements 0 and 1
println fibonacci(stream).take(10).force()
// [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
def fibonacci(n) {
Stream.iterate([0, 1]) {
def (first, second) = it
[second, first + second]
}.map {
def (first, second) = it
first
}.take(n)
}
println fibonacci(10).force()
// [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
First 10 Fibonacci Nos.
Definition as suggested by Christopher Grande
Split
def split(Closure predicate) {
fold([Stream.Empty, Stream.Empty]) { streams, elem ->
def (yays, nays) = streams
if (predicate(elem)) [yays << elem, nays]
else [yays, nays << elem]
}
}
} // End of Stream class
def stream = Stream.from(0).take(10)
def (evens, odds) = stream.split { it % 2 == 0 }
println odds.force() // [8, 6, 4, 2, 0]
println evens.force() // [9, 7, 5, 3, 1]
Concat
def leftShift(Stream<?> other) {
if (isEmpty()) other
else new Stream(head(), {-> tail() << other})
}
} // End of Stream class
def nums = Stream.of(1, 2, 3)
def chars = Stream.of('a', 'b', 'c')
println ((nums << chars).force()) // [1, 2, 3, a, b, c]
flatMap
// fn: T -> Stream<U>
def flatMap(Closure fn) {
if (isEmpty()) Stream.Empty
else fn(head()) << tail().flatMap(fn)
}
} // End of Stream class
def nums = Stream.of(1, 2)
println nums.flatMap { it -> cs }.force() // [a, b, a, b]
println nums.flatMap { n ->
Stream.of('a', 'b').map { c ->
[c, n]
}
}.force() // [[a, 1], [b, 1], [a, 2], [b, 2]]
Recap
Thank-You!
Stream implementation shown in these slides is available on:
https://github.com/CodeJugalbandi/FunctionalProgramming/blob/master/melodies/lazy_sequences/Stream.groovy
References
Programming Groovy
Venkat Subramaniam
Groovy In Action
Dierk König
Structure and
Interpretation of
Computer Programs
Abelson, Sussman and
Sussman
Functional Prog.
Coursera Course
Martin Odersky
Functional Prog. with
Groovy
Arturo Herrero
On Understanding
Types, Data
Abstraction &
Polymorphism
Luca Cardelli, Peter
Wegner

Weitere ähnliche Inhalte

Was ist angesagt?

Douglas Crockford Presentation Goodparts
Douglas Crockford Presentation GoodpartsDouglas Crockford Presentation Goodparts
Douglas Crockford Presentation GoodpartsAjax Experience 2009
 
Integrated Language Definition Testing: Enabling Test-Driven Language Develop...
Integrated Language Definition Testing: Enabling Test-Driven Language Develop...Integrated Language Definition Testing: Enabling Test-Driven Language Develop...
Integrated Language Definition Testing: Enabling Test-Driven Language Develop...lennartkats
 
Programming Paradigms
Programming ParadigmsProgramming Paradigms
Programming ParadigmsJaneve George
 
Thinking Like a Programmer
Thinking Like a ProgrammerThinking Like a Programmer
Thinking Like a ProgrammerCate Huston
 
Scala - the good, the bad and the very ugly
Scala - the good, the bad and the very uglyScala - the good, the bad and the very ugly
Scala - the good, the bad and the very uglyBozhidar Bozhanov
 
Web development basics (Part-4)
Web development basics (Part-4)Web development basics (Part-4)
Web development basics (Part-4)Rajat Pratap Singh
 
Remix Your Language Tooling (JSConf.eu 2012)
Remix Your Language Tooling (JSConf.eu 2012)Remix Your Language Tooling (JSConf.eu 2012)
Remix Your Language Tooling (JSConf.eu 2012)lennartkats
 
Functional programming with Java 8
Functional programming with Java 8Functional programming with Java 8
Functional programming with Java 8Talha Ocakçı
 
Common Programming Paradigms
Common Programming ParadigmsCommon Programming Paradigms
Common Programming ParadigmsSuheyl Zafar
 
Advanced Javascript
Advanced JavascriptAdvanced Javascript
Advanced JavascriptDhruvin Shah
 
Kotlin & arrow: the functional way
Kotlin & arrow:  the functional wayKotlin & arrow:  the functional way
Kotlin & arrow: the functional waynluaces
 
Metaprogramming in Ruby
Metaprogramming in RubyMetaprogramming in Ruby
Metaprogramming in RubyVolodymyr Byno
 
Scala the-good-parts
Scala the-good-partsScala the-good-parts
Scala the-good-partsFuqiang Wang
 
Test-driven language development
Test-driven language developmentTest-driven language development
Test-driven language developmentlennartkats
 
Java Building Blocks
Java Building BlocksJava Building Blocks
Java Building BlocksCate Huston
 

Was ist angesagt? (20)

Douglas Crockford Presentation Goodparts
Douglas Crockford Presentation GoodpartsDouglas Crockford Presentation Goodparts
Douglas Crockford Presentation Goodparts
 
Integrated Language Definition Testing: Enabling Test-Driven Language Develop...
Integrated Language Definition Testing: Enabling Test-Driven Language Develop...Integrated Language Definition Testing: Enabling Test-Driven Language Develop...
Integrated Language Definition Testing: Enabling Test-Driven Language Develop...
 
Programming Paradigms
Programming ParadigmsProgramming Paradigms
Programming Paradigms
 
Thinking Like a Programmer
Thinking Like a ProgrammerThinking Like a Programmer
Thinking Like a Programmer
 
Scala - the good, the bad and the very ugly
Scala - the good, the bad and the very uglyScala - the good, the bad and the very ugly
Scala - the good, the bad and the very ugly
 
Web development basics (Part-4)
Web development basics (Part-4)Web development basics (Part-4)
Web development basics (Part-4)
 
Why Ruby
Why RubyWhy Ruby
Why Ruby
 
Remix Your Language Tooling (JSConf.eu 2012)
Remix Your Language Tooling (JSConf.eu 2012)Remix Your Language Tooling (JSConf.eu 2012)
Remix Your Language Tooling (JSConf.eu 2012)
 
Programming paradigms
Programming paradigmsProgramming paradigms
Programming paradigms
 
From Java to Kotlin
From Java to KotlinFrom Java to Kotlin
From Java to Kotlin
 
Functional programming with Java 8
Functional programming with Java 8Functional programming with Java 8
Functional programming with Java 8
 
Common Programming Paradigms
Common Programming ParadigmsCommon Programming Paradigms
Common Programming Paradigms
 
API Design
API DesignAPI Design
API Design
 
Advanced Javascript
Advanced JavascriptAdvanced Javascript
Advanced Javascript
 
Kotlin & arrow: the functional way
Kotlin & arrow:  the functional wayKotlin & arrow:  the functional way
Kotlin & arrow: the functional way
 
Metaprogramming in Ruby
Metaprogramming in RubyMetaprogramming in Ruby
Metaprogramming in Ruby
 
Scala the-good-parts
Scala the-good-partsScala the-good-parts
Scala the-good-parts
 
Test-driven language development
Test-driven language developmentTest-driven language development
Test-driven language development
 
Java Building Blocks
Java Building BlocksJava Building Blocks
Java Building Blocks
 
Switch case and looping
Switch case and loopingSwitch case and looping
Switch case and looping
 

Ähnlich wie Grooming with Groovy

Writing Readable Code
Writing Readable CodeWriting Readable Code
Writing Readable Codeeddiehaber
 
Groovy / comparison with java
Groovy / comparison with javaGroovy / comparison with java
Groovy / comparison with javaLiviu Tudor
 
Ruby Metaprogramming - OSCON 2008
Ruby Metaprogramming - OSCON 2008Ruby Metaprogramming - OSCON 2008
Ruby Metaprogramming - OSCON 2008Brian Sam-Bodden
 
Modern_2.pptx for java
Modern_2.pptx for java Modern_2.pptx for java
Modern_2.pptx for java MayaTofik
 
Rootcon X - Reverse Engineering Swift Applications
Rootcon X - Reverse Engineering Swift ApplicationsRootcon X - Reverse Engineering Swift Applications
Rootcon X - Reverse Engineering Swift Applicationseightbit
 
Object-Oriented Programming with Java UNIT 1
Object-Oriented Programming with Java UNIT 1Object-Oriented Programming with Java UNIT 1
Object-Oriented Programming with Java UNIT 1SURBHI SAROHA
 
An Introduction to Groovy for Java Developers
An Introduction to Groovy for Java DevelopersAn Introduction to Groovy for Java Developers
An Introduction to Groovy for Java DevelopersKostas Saidis
 
Future Programming Language
Future Programming LanguageFuture Programming Language
Future Programming LanguageYLTO
 
Hack in the Box GSEC 2016 - Reverse Engineering Swift Applications
Hack in the Box GSEC 2016 - Reverse Engineering Swift ApplicationsHack in the Box GSEC 2016 - Reverse Engineering Swift Applications
Hack in the Box GSEC 2016 - Reverse Engineering Swift Applicationseightbit
 
20 most important java programming interview questions
20 most important java programming interview questions20 most important java programming interview questions
20 most important java programming interview questionsGradeup
 

Ähnlich wie Grooming with Groovy (20)

Groovy And Grails
Groovy And GrailsGroovy And Grails
Groovy And Grails
 
Writing Readable Code
Writing Readable CodeWriting Readable Code
Writing Readable Code
 
Interview-QA.pptx
Interview-QA.pptxInterview-QA.pptx
Interview-QA.pptx
 
Groovy / comparison with java
Groovy / comparison with javaGroovy / comparison with java
Groovy / comparison with java
 
Ruby Metaprogramming - OSCON 2008
Ruby Metaprogramming - OSCON 2008Ruby Metaprogramming - OSCON 2008
Ruby Metaprogramming - OSCON 2008
 
scala-intro
scala-introscala-intro
scala-intro
 
JavaScript Variables
JavaScript VariablesJavaScript Variables
JavaScript Variables
 
Viva file
Viva fileViva file
Viva file
 
All of Javascript
All of JavascriptAll of Javascript
All of Javascript
 
Switch case looping
Switch case loopingSwitch case looping
Switch case looping
 
Modern_2.pptx for java
Modern_2.pptx for java Modern_2.pptx for java
Modern_2.pptx for java
 
Java basics
Java basicsJava basics
Java basics
 
Rootcon X - Reverse Engineering Swift Applications
Rootcon X - Reverse Engineering Swift ApplicationsRootcon X - Reverse Engineering Swift Applications
Rootcon X - Reverse Engineering Swift Applications
 
Object-Oriented Programming with Java UNIT 1
Object-Oriented Programming with Java UNIT 1Object-Oriented Programming with Java UNIT 1
Object-Oriented Programming with Java UNIT 1
 
Java notes
Java notesJava notes
Java notes
 
An Introduction to Groovy for Java Developers
An Introduction to Groovy for Java DevelopersAn Introduction to Groovy for Java Developers
An Introduction to Groovy for Java Developers
 
Future Programming Language
Future Programming LanguageFuture Programming Language
Future Programming Language
 
Introduction to JavaScript Programming
Introduction to JavaScript ProgrammingIntroduction to JavaScript Programming
Introduction to JavaScript Programming
 
Hack in the Box GSEC 2016 - Reverse Engineering Swift Applications
Hack in the Box GSEC 2016 - Reverse Engineering Swift ApplicationsHack in the Box GSEC 2016 - Reverse Engineering Swift Applications
Hack in the Box GSEC 2016 - Reverse Engineering Swift Applications
 
20 most important java programming interview questions
20 most important java programming interview questions20 most important java programming interview questions
20 most important java programming interview questions
 

Mehr von Dhaval Dalal

Test Pyramid in Microservices Context
Test Pyramid in Microservices ContextTest Pyramid in Microservices Context
Test Pyramid in Microservices ContextDhaval Dalal
 
Booting into functional programming
Booting into functional programmingBooting into functional programming
Booting into functional programmingDhaval Dalal
 
Currying and Partial Function Application (PFA)
Currying and Partial Function Application (PFA)Currying and Partial Function Application (PFA)
Currying and Partial Function Application (PFA)Dhaval Dalal
 
Creating Lazy stream in CSharp
Creating Lazy stream in CSharpCreating Lazy stream in CSharp
Creating Lazy stream in CSharpDhaval Dalal
 
Json Viewer Stories
Json Viewer StoriesJson Viewer Stories
Json Viewer StoriesDhaval Dalal
 
Mars rover-extension
Mars rover-extensionMars rover-extension
Mars rover-extensionDhaval Dalal
 
How Is Homeopathy Near To Yoga?
How Is Homeopathy Near To Yoga?How Is Homeopathy Near To Yoga?
How Is Homeopathy Near To Yoga?Dhaval Dalal
 
Approaching ATDD/BDD
Approaching ATDD/BDDApproaching ATDD/BDD
Approaching ATDD/BDDDhaval Dalal
 
Paradigms Code jugalbandi
Paradigms Code jugalbandiParadigms Code jugalbandi
Paradigms Code jugalbandiDhaval Dalal
 
Data Reconciliation
Data ReconciliationData Reconciliation
Data ReconciliationDhaval Dalal
 
DRYing to Monad in Java8
DRYing to Monad in Java8DRYing to Monad in Java8
DRYing to Monad in Java8Dhaval Dalal
 
4-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr2015
4-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr20154-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr2015
4-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr2015Dhaval Dalal
 
Jumping-with-java8
Jumping-with-java8Jumping-with-java8
Jumping-with-java8Dhaval Dalal
 
3-CodeJugalbandi-currying-pfa-healthycodemagazine#mar2015
3-CodeJugalbandi-currying-pfa-healthycodemagazine#mar20153-CodeJugalbandi-currying-pfa-healthycodemagazine#mar2015
3-CodeJugalbandi-currying-pfa-healthycodemagazine#mar2015Dhaval Dalal
 
CodeJugalbandi-Sequencing-HealthyCode-Magazine-Feb-2015
CodeJugalbandi-Sequencing-HealthyCode-Magazine-Feb-2015CodeJugalbandi-Sequencing-HealthyCode-Magazine-Feb-2015
CodeJugalbandi-Sequencing-HealthyCode-Magazine-Feb-2015Dhaval Dalal
 
CodeJugalbandi-Expression-Problem-HealthyCode-Magazine#Jan-2015-Issue
CodeJugalbandi-Expression-Problem-HealthyCode-Magazine#Jan-2015-IssueCodeJugalbandi-Expression-Problem-HealthyCode-Magazine#Jan-2015-Issue
CodeJugalbandi-Expression-Problem-HealthyCode-Magazine#Jan-2015-IssueDhaval Dalal
 
The tao-of-transformation-workshop
The tao-of-transformation-workshopThe tao-of-transformation-workshop
The tao-of-transformation-workshopDhaval Dalal
 

Mehr von Dhaval Dalal (20)

Test Pyramid in Microservices Context
Test Pyramid in Microservices ContextTest Pyramid in Microservices Context
Test Pyramid in Microservices Context
 
Code Retreat
Code RetreatCode Retreat
Code Retreat
 
Booting into functional programming
Booting into functional programmingBooting into functional programming
Booting into functional programming
 
Currying and Partial Function Application (PFA)
Currying and Partial Function Application (PFA)Currying and Partial Function Application (PFA)
Currying and Partial Function Application (PFA)
 
Creating Lazy stream in CSharp
Creating Lazy stream in CSharpCreating Lazy stream in CSharp
Creating Lazy stream in CSharp
 
Json Viewer Stories
Json Viewer StoriesJson Viewer Stories
Json Viewer Stories
 
Value Objects
Value ObjectsValue Objects
Value Objects
 
Mars rover-extension
Mars rover-extensionMars rover-extension
Mars rover-extension
 
How Is Homeopathy Near To Yoga?
How Is Homeopathy Near To Yoga?How Is Homeopathy Near To Yoga?
How Is Homeopathy Near To Yoga?
 
Approaching ATDD/BDD
Approaching ATDD/BDDApproaching ATDD/BDD
Approaching ATDD/BDD
 
Paradigms Code jugalbandi
Paradigms Code jugalbandiParadigms Code jugalbandi
Paradigms Code jugalbandi
 
Data Reconciliation
Data ReconciliationData Reconciliation
Data Reconciliation
 
DRYing to Monad in Java8
DRYing to Monad in Java8DRYing to Monad in Java8
DRYing to Monad in Java8
 
CodeRetreat
CodeRetreatCodeRetreat
CodeRetreat
 
4-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr2015
4-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr20154-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr2015
4-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr2015
 
Jumping-with-java8
Jumping-with-java8Jumping-with-java8
Jumping-with-java8
 
3-CodeJugalbandi-currying-pfa-healthycodemagazine#mar2015
3-CodeJugalbandi-currying-pfa-healthycodemagazine#mar20153-CodeJugalbandi-currying-pfa-healthycodemagazine#mar2015
3-CodeJugalbandi-currying-pfa-healthycodemagazine#mar2015
 
CodeJugalbandi-Sequencing-HealthyCode-Magazine-Feb-2015
CodeJugalbandi-Sequencing-HealthyCode-Magazine-Feb-2015CodeJugalbandi-Sequencing-HealthyCode-Magazine-Feb-2015
CodeJugalbandi-Sequencing-HealthyCode-Magazine-Feb-2015
 
CodeJugalbandi-Expression-Problem-HealthyCode-Magazine#Jan-2015-Issue
CodeJugalbandi-Expression-Problem-HealthyCode-Magazine#Jan-2015-IssueCodeJugalbandi-Expression-Problem-HealthyCode-Magazine#Jan-2015-Issue
CodeJugalbandi-Expression-Problem-HealthyCode-Magazine#Jan-2015-Issue
 
The tao-of-transformation-workshop
The tao-of-transformation-workshopThe tao-of-transformation-workshop
The tao-of-transformation-workshop
 

Kürzlich hochgeladen

Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024The Digital Insurer
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
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
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
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
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piececharlottematthew16
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
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
 
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
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embeddingZilliz
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesZilliz
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr LapshynFwdays
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 

Kürzlich hochgeladen (20)

Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
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
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
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
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piece
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.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
 
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!
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embedding
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector Databases
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 

Grooming with Groovy

  • 1. Grooming With Groovy Come,Code Along! dhaval.dalal@software-artisan.com @softwareartisan
  • 2. Hello World… Concise - convey more in less Groovy Classes Are Java Classes Everything is an object.
  • 3. Flexibility Dynamic Language Program extension at runtime by altering behaviour and structure of objects/types - “Open Classes” Code synthesis Add code at runtime As opposed to manipulating byte code in Static Languages like Java. Groovy’s extension to JDK is called GDK
  • 4. Uncertainty Pimp(extend) my Library Extending the class - additive operation. Monkey Patching Redefining things again - Don’t cause fires! Break glass in case of fire - reach out for this meta-programming hammer only then. Adding != Redefining
  • 5. Typing 101 Type? How do I interpret data in that block of memory and what operations can I perform on it? Safety? Any attempt to misinterpret data is caught at compile time OR generates a well-specified error at runtime.
  • 6. Dynamic & Static Typing Statically Typed Language Type of every expression can be determined by static program analysis (before it runs). Compile-time type checking. Align types naturally or by casting. Dynamically Typed Runtime type checking, not compile-time checking
  • 7. Dynamic Typing Infers Type based on context. Numbers and Decimals We rely on static typing for code safety, but it still can fail us. Generics ArrayStoreException Dynamic & Static Typing
  • 8. Optional & Duck Typing Optionally Typed Specify when you need, and leave it to Groovy to figure it out where you don’t care. Duck Typing Don’t need a type to invoke a method on object. If its there, you can invoke it Objects behave as demanded of them in a given context, rather than ensuring that they are of a specific type. You can treat it like a dog or even god.
  • 9. Ram (Static) Balram (Dynamic) Static typing catches bugs with the compiler and keeps you out of trouble. Static typing only catches some bugs, and you can’t trust the compiler to do your testing Static languages are easier to read because they’re more explicit about what the code does. Dynamic languages are easier to read because you write less code. At least I know that the code compiles. Just because the code compiles doesn’t mean it runs. I trust the static typing to make sure my team writes good code. The compiler doesn’t stop you from writing bad code. Debugging an unknown object is impossible. Debugging overly complex object hierarchies is unbearable. Compiler bugs happen at midmorning in my office; runtime bugs happen at midnight for my customers. There’s no replacement for testing, and unit tests find more issues than the compiler ever could. Source: http://www.smashingmagazine.com/2013/04/18/introduction-to-programming-type-systems/
  • 10. Use correct typing to solve the problem at hand Doesn’t matter if you have to use more than one at a given time. Use Static typing where possible, Dynamic typing when needed - Eric Meijer Avoid Polarization Like a good manager, play on strengths of each :-) Dynamic or Static Typing?
  • 11. Weakly Typed The type of a value depends on how it is used. Can mix operations between mismatched types without explicit conversion C lets you define object types as structures, but it doesn’t do much to enforce or remember them. C automatically converts between many types. http://c2.com/cgi/wiki?WeakAndStrongTyping
  • 12. Strongly Typed Language A Language in which all expressions are type consistent is Strongly Typed. A value has a type and that type cannot change. What you can do to a value depends on the type of the value. Can’t mix operations between mismatched types, if you do, the runtime catches you. You must convert explicitly. But, being liberal with type conversions doesn't really mean the same as saying that the language is weakly typed! http://c2.com/cgi/wiki?WeakAndStrongTyping
  • 14. Strings in Groovy Literal Strings String Interpolation GString - Nah, stop fantasising! Allow in-place evaluation of expressions…and for that you have to use the $ ;-) Multi-line String Lazy Evaluation Slashy Strings
  • 15. Match found! Pattern from String use operator ~ Determine a match =~ For exact match ==~ Regex Readability Prefer Slashy strings over normal ones
  • 16. Truth & Difficult Situations Groovy Truth Dealing with Exceptions No force to catch Java’s Checked Exceptions Dealing with Absent Values null is an object, try null.getClass() and toString() null-safe operator (?.)
  • 17. Methods and Parameters Properties (Getters and Setters) Trailing Optional Parameters Positional parameters - @TupleConstructor @Cannonical = @EqualsAndHashCode, @ToString and @TupleConstructor
  • 18. Hello Operator! Preserve semantics when using Operator overloading. When someone asks you - what does this operator do? You know the answer :-) Use it to harmonise with the domain/ context Typically very nice for value objects.
  • 19. Multi-Methods Also called as Multiple Dispatch. Dispatch based on type of the receiver. Example, Java/C#/Scala and based on Run-time Type of the arguments, not on Compile-time type (as in Java). Example, Clojure The equals method.
  • 20. A Peek at GDK Producing and Consuming XML Spawning Processes Using Files Using Configuration Avoid properties hell. Using SQL
  • 21. Compose behaviours, Don’t inherit @Delegate @Mixin (< 2.3) Traits (>= 2.3, @Mixin deprecated) trait -> Language keyword, not an AST transformation
  • 22. Traits Like interfaces, they cannot be instantiated. However, unlike interfaces, they can have implementation and state. Can contain abstract methods. Classes can inherit multiple traits or implement at run-time. Trait can extend another trait and implement interfaces as well. Methods are “real” and visible from Java as well.
  • 23. Closures Objects = data + behavior, whereas Closures = behavior. Convert Methods to Closures. Using the object.&method Static, Instance or in Script methods. The with closure.
  • 24. Closures in Action AOP around style using Closures. Loan My Resource - like try-with- resources in Java. Closure as an interface. Query Closure to find maximumNumberOfParameters parameterTypes and alter the response accordingly - polymorphic closures.
  • 25. More on Closures Memoized Closures and @Memoized methods Remember me and I’ll help you! Trampolined Closures and @TailRecursive methods Don’t jump that high, but instead jump many times!
  • 26. More on Closures Curried Closures Spice that helps us re-shape and re- purpose! curry, rcurry Composing Closures The way to tackle complexity! >> and <<
  • 27. When to use Closures? Eliminating Dependencies Esp. on single method interfaces Building Declarative APIs and Preserving encapsulation. External iterators or getters expose innards of an aggregate, instead use internal iterators and call closure. Building DSLs Using HOFs it becomes easy to construct DSLs Lazy Evaluation
  • 28. Hello Collections… Lists - [] , Maps - [:], Ranges - (a..b), Sets Tuples Iterate each element. each, reverseEach, eachWithIndex Transform each element. collect, collectNested, collectMany and collectEntries
  • 29. Collection Operations Retrieve Elements that satisfy certain criterion find, findAll Transform using predicate (collect + ~find) findResult(s) Combine adjacent elements sum, inject, min, max
  • 30. Collection Ops Queries contains, count, any, every Mutating Operations reverse, removeAll, retainAll Generators collate, permutations, combinations, subsequences, transpose
  • 31. Collection Ops Set-Style Operations intersect, disjoint, plus (union) Distinct and Order By unique, sort Partition Collection to Map groupBy, groupEntriesBy, countBy split and join drop, take, dropWhile, takeWhile
  • 32. Spreading Collections The Spread-dot Operator (*.) Array and List as varargs The Spread Operator (*) Map as an Interface. Very useful when Stubbing
  • 33. FP in Groovy Like in other languages Java/C#/Ruby etc…, in-place mutation is a standing invitation in Groovy too! Its hard to avoid falling into that trap. One has to work hard to bring immutability. A change to Immutable Object produces another Immutable Object Promotes caching of objects - Flyweights. Promotes concurrent operations.
  • 34. FP in Groovy Use Expressions wherever possible Statements effect change by mutation thus encourage mutability Expressions evaluate and return value thus encourage immutability Use Pure Functions wherever possible Order of program evaluation Referential Transparency Memoization
  • 35. Immutability Immutability and Pure functions make it easier to reason about programs Use @Immutable to make a class immutable
  • 36. Immutability Collection APIs Prefer Immutable version Over Mutable version Adding + <<, addAll Removing - removeAll Sorting sort(false) sort() Reversing reverse() reverse(false)
  • 37. Lazy Evaluation Lazy Evaluation (by-name) Don’t compute until actually required. Lazy Evaluation (by-need) Store the result of computation for future use and avoid re-computation @Lazy AST Transformation Needs to be initialised at the time of declaration
  • 38. Being Lazy is efficient Lazy defaults on Lists Lazy Sequences A sequence whose tail is evaluated only someone wants to know its value. Materialise on demand to avoid unnecessary computation of tail.
  • 39. Lets implement Immutable Stream Stream implementation shown in these slides is available on: https://github.com/CodeJugalbandi/FunctionalProgramming/blob/master/melodies/lazy_sequences/Stream.groovy
  • 40. Lets implement Immutable Stream How can we implement a lazy List in Groovy? 1 ? Stream implementation shown in these slides is available on: https://github.com/CodeJugalbandi/FunctionalProgramming/blob/master/melodies/lazy_sequences/Stream.groovy
  • 41. Lets implement Immutable Stream How can we implement a lazy List in Groovy? By using closure on the tail of the list. Additionally for performance - use Memoization on that closure. Evaluate tail 1 ? 1 * 2 ? Stream implementation shown in these slides is available on: https://github.com/CodeJugalbandi/FunctionalProgramming/blob/master/melodies/lazy_sequences/Stream.groovy
  • 42. Ingredients for Lazy Evaluation Groovy uses eager evaluation for method arguments. Args are evaluated before passing to the method. To delay the evaluation of method arguments (lazy), wrap them in Closure Invoke the closure explicitly in the method when we need the evaluation result.
  • 43. Ingredients for Lazy Evaluation Wrap in Closure for Lazy Calls for storing result of evaluation and avoiding computation again, performance optimisation CAVEAT: Only for pure functions! Evaluation on Closure Call
  • 44. Stream with head and lazy evaluated tail As Streams are immutable we can structurally share the earlier stream.
  • 45. Stream(T head, Stream<T> tail) { _head = head _tail = {-> tail}.memoize() } new Stream<Integer>(1, new Stream(null, null)) Stream(T head, Closure tail) { _head = head _tail = tail.memoize() } new Stream<Integer>(1, {-> new Stream(null, {-> null})}) Causes Immediate Evaluation - Eager Hence wrap the tail stream in a Closure at the time of Stream Creation - Lazy
  • 47. Define toString String toString() { if (isEmpty()) ‘[]’ else “[${head()}, ?]” } } // End of Stream class def empty = Stream.Empty println empty // [] def singleton = new Stream(1, {-> empty}) println singleton // [1, ?] def couple = new Stream(2, {-> singleton}) println couple // [2, ?]
  • 48. def leftShift(T element) { new Stream(element, {-> this}) } } // End of Stream class def stream = Stream.Empty << 1 << 2 println stream // [2, ?] println stream.head() // 2 println stream.tail() // [1, ?] println stream.tail().tail() // [] Consing to Stream Prepend (Cons)
  • 49. Construct a Stream from few elements static def of(T ...ts) { def stream = Stream.Empty ts.reverseEach { stream = stream << it } stream } } // End of Stream class def stream = Stream.of(1, 2, 3, 4) println stream // [1, ?]
  • 50. Construct a Stream from Range static def range(Range range, Integer step) { Stream.of(*range.step(step)) } } // End of Stream class println Stream.range('a'..'z') println Stream.range(‘A'..'Z', 2) println Stream.range(-10..5) println Stream.range(new Date("12-Dec-2012")..new Date("19-Jan-2013"))
  • 51. Force entire Stream to Evaluate def force() { if (isEmpty()) [] else [head()] + tail().force() } } // End of Stream class def empty = Stream.Empty println empty // [] def stream = Stream.of(1, 2, 3, 4) println stream.force() // [1, 2, 3, 4]
  • 52. Drop first few and take the rest def drop(howMany) { if (isEmpty() || howMany <= 0) this else tail().drop(howMany - 1) } } // End of Stream class def empty = Stream.Empty println empty.drop(2).force() // [] def stream = Stream.of(1, 2, 3, 4) println stream.drop(2) // [3, ?] println stream.drop(2).force() // [3, 4] println stream.drop(9).force() // []
  • 53. stream as a function of its index def call(index) { def list = take(index + 1).force() if (index > list.size() - 1) throw new Exception(“Index $index out of bounds”) list[index] } } // End of Stream class def empty = Stream.Empty println empty(2) // Exception: Index 2 out of bounds def stream = Stream.of(1, 2, 3, 4) println stream(0) // 1 println stream(3) // 4 println stream(4) // Exception: Index 4 out of bounds
  • 54. Combining Adjacent Elements Using fold def fold(acc, Closure fn) { if (isEmpty()) acc else tail().fold(fn(acc, head()), fn) } } // End of Stream class def stream = Stream.of(1, 2, 3, 4) // Sum of all elements println stream.fold(0) { acc, elem -> acc + elem } // 10 // Product of all elements println stream.fold(1) { acc, elem -> acc * elem } // 24
  • 55. TailRecursive fold @TailRecursive def fold(stream = this, acc, Closure fn) { if (stream.isEmpty()) acc else fold(stream.tail(), fn(acc, stream.head()), fn) } } // End of Stream class def stream = Stream.of(1, 2, 3, 4) // Sum of all elements println stream.fold(0) { acc, elem -> acc + elem } // 10 // Product of all elements println stream.fold(1) { acc, elem -> acc * elem } // 24
  • 56. Express force in terms of fold But why do we do this? def force() { fold([]) { acc, elem -> acc + elem } } } // End of Stream class def empty = Stream.Empty println empty // [] def stream = empty << 1 << 2 << 3 << 4 println stream.force() // [4, 3, 2, 1]
  • 57. force() [4, ?] [4] + force() [3, ?] [4] + [3] + force() [2, ?] [4] + [3] + [2] + force() [1, ?] [4] + [3] + [2] + [1] + force() [] [4] + [3] + [2] + ([1] + []) [4] + [3] + ([2] + [1]) [4] + ([3] + [2, 1]) [4] + [3, 2, 1] [4, 3, 2, 1] fold [4, ?] [] fold [3, ?] [4] fold [2, ?] [4, 3] fold [1, ?] [4, 3, 2] fold [] [4, 3, 2, 1] [4, 3, 2, 1] Shape of the process becomes iterative after expressing it in terms of fold. Earlier force implementation was a recursive process. Shapes of Processes Build-up on stack like this causes it to overflow State passed as parameter State stored on stack
  • 58. Reverse def reverse() { fold(Stream.Empty) { stream, elem -> stream << elem } } } // End of Stream class def stream = Stream.of(1, 2, 3, 4) println stream.reverse() // [4, ?] println stream.reverse().force() // [4, 3, 2, 1]
  • 59. TailRecursive foldN @TailRecursive def foldN(stream = this, howMany, acc, Closure fn) { if (stream.isEmpty() || howMany <= 0) acc else foldN(stream.tail(), howMany - 1, fn(acc, stream.head()), fn) } } // End of Stream class def stream = Stream.of(1, 2, 3, 4) // Sum of 2 elements println stream.foldN(2, 0) { acc, elem -> acc + elem } // 3 // Product of 2 elements println stream.foldN(2, 1) { acc, elem -> acc * elem } // 2
  • 60. Express drop in terms of foldN def drop(howMany) { foldN(howMany, this) { stream, elem -> stream.tail() } } } // End of Stream class def empty = Stream.Empty println empty.drop(2).force() // [] def stream = Stream.of(1, 2, 3, 4) println stream.drop(2) // [3, ?] println stream.drop(2).force() // [3,4] println stream.drop(9).force() // []
  • 61. Filter elements by criteria def filter(Closure predicate) { if (isEmpty()) Stream.Empty else if (predicate(head())) new Stream(head(), {-> tail().filter(predicate)}) else tail().filter(predicate) } } // End of Stream class def stream = Stream.of(1, 2, 3, 4) println stream.filter { it % 2 == 0 } // [2, ?] println stream.filter { it % 2 != 0 }.force() // [1, 3]
  • 62. Take while predicate holds def takeWhile(Closure predicate) { if (isEmpty()) Stream.Empty else if (predicate(head())) new Stream(head(), {-> tail().takeWhile(predicate)}) else Stream.Empty } } // End of Stream class def empty = Stream.Empty println empty.takeWhile { it == 1 } // [] def stream = Stream.of(1, 1, 1, 2, 1, 2) println stream.takeWhile { it == 1 } // [1, ?] println stream.takeWhile { it == 1 }.force() // [1, 1, 1]
  • 63. Drop while predicate holds def dropWhile(Closure predicate) { if (isEmpty()) Stream.Empty else if (predicate(head())) tail().dropWhile(predicate) else this } } // End of Stream class def empty = Stream.Empty println empty.dropWhile { it == 1 } // [] def stream = def stream = Stream.of(1, 1, 1, 2, 1, 2) println stream.dropWhile { it == 1 } // [2, ?] println stream.dropWhile { it == 1 }.force() // [2, 1, 2]
  • 64. Transform each Element def map(Closure fn) { if (isEmpty()) Stream.Empty else new Stream(fn(head()), {-> tail().map(fn)}) } } // End of Stream class def stream = Stream.of(1, 2, 3, 4) println stream.map { it * 2 } // [1, ?] println stream.map { it * it }.force() // [1, 4, 9, 16]
  • 65. Transform using Predicate def collect(Closure predicate) { if (isEmpty()) Stream.Empty else if (predicate(head())) new Stream(predicate(head()), {-> tail().collect(predicate)}) else tail().collect(predicate) } } // End of Stream class def stream = Stream.of(1, 2, 3, 4) def squaredEvens = stream.collect { if (it % 2 == 0) it * it // Square Evens, leave Odds else null // Groovy truth expression that evaluates to false } println squaredEvens // [4, ?] println squaredEvens.force() // [4, 16]
  • 66. Iterate each element def forEach(Closure fn) { if (isEmpty()) Stream.Empty else { fn(head()) tail().forEach(fn) } } } // End of Stream class def stream = Stream.of(1, 2, 3, 4) stream.forEach { print it } // 1234
  • 67. Non-Terminating Recursion static def generate(Closure fn) { new Stream(fn(), {-> generate(fn)}) } } // End of Stream class def rnd = new java.util.Random() def stream = Stream.generate { rnd.nextInt(10) } println stream.take(5).force()
  • 68. Non-Terminating Recursion static def iterate(initial, Closure fn) { new Stream(initial, {-> iterate(fn(initial), fn) }) } static def from(n) { iterate(n) { it + 1 } } } // End of Stream class
  • 69. Infinitely Lazy Streams, unlike lists (eager), are lazy. Streams, unlike lists (finite), are infinite. They have a starting point, but no end. // The below will not terminate Stream.from(4).forEach { println it }
  • 70. Finite from Infinite Take what we are interested in and leave the rest in ether! def numbersFrom4 = Stream.from(4) println numbersFrom4.take(2).force() // [4, 5] println numbersFrom4.take(5).force() // [4, 5, 6, 7, 8]
  • 71. Find first 6 primes using the Sieve of Eratosthenes Hint: Use Stream created earlier http://world.mathigon.org/Prime_Numbers
  • 72. Sieve def sieve(s) { def first = s.head() def rest = s.tail().filter { it % first != 0 } new Stream(first, {-> sieve(rest)}) } def primes = sieve(Stream.from(2)).take(6) println primes.force() // [2, 3, 5, 7, 11, 13]
  • 73. Non-Memoized Tail Serious Performance hit as tail is wrapped in closure and if when called several times the stream is recomputed each time upon call.
  • 75. Zip two Streams def zip(Stream<T> that) { if (isEmpty() || that.isEmpty()) Stream.Empty else new Stream(new Tuple(head(), that.head()), {-> tail().zip(that.tail()) }) } } // End of Stream class def s1 = Stream.of(0, 1, 2) def s2 = Stream.of(4, 5, 6) def zipped = s1.zip(s2) println zipped // [[0, 4], ?] println zipped.tail() // [[1, 5], ?] println zipped.force() // [0, 4, 1, 5, 2, 6] println zipped.force().collate(2) // [[2, 6], [1, 5], [0,4]] // Sum of 2 streams println zipped.map { def (first, second) = it first + second }.force() // [4, 6, 8]
  • 76. Zip with Index def zipWithIndex() { zip(from(0)) } } // End of Stream class def stream = Stream.of('a', 'b', 'c', 'd') stream.zipWithIndex().forEach { print it // [a, 0][b, 1][c, 2][d, 3] }
  • 77. def fibonacci(s) { def next = s.zip(s.tail()).map { def (first, second) = it first + second } def rest = s << next.head() new Stream(s.head(), {-> fibonacci(rest)}) } First 10 Fibonacci Nos. https://www.haskell.org/tutorial/functions.html def stream = Stream.from(0).take(2) println stream.force() // [0, 1] // Start with seed elements 0 and 1 println fibonacci(stream).take(10).force() // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
  • 78. def fibonacci(n) { Stream.iterate([0, 1]) { def (first, second) = it [second, first + second] }.map { def (first, second) = it first }.take(n) } println fibonacci(10).force() // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] First 10 Fibonacci Nos. Definition as suggested by Christopher Grande
  • 79. Split def split(Closure predicate) { fold([Stream.Empty, Stream.Empty]) { streams, elem -> def (yays, nays) = streams if (predicate(elem)) [yays << elem, nays] else [yays, nays << elem] } } } // End of Stream class def stream = Stream.from(0).take(10) def (evens, odds) = stream.split { it % 2 == 0 } println odds.force() // [8, 6, 4, 2, 0] println evens.force() // [9, 7, 5, 3, 1]
  • 80. Concat def leftShift(Stream<?> other) { if (isEmpty()) other else new Stream(head(), {-> tail() << other}) } } // End of Stream class def nums = Stream.of(1, 2, 3) def chars = Stream.of('a', 'b', 'c') println ((nums << chars).force()) // [1, 2, 3, a, b, c]
  • 81. flatMap // fn: T -> Stream<U> def flatMap(Closure fn) { if (isEmpty()) Stream.Empty else fn(head()) << tail().flatMap(fn) } } // End of Stream class def nums = Stream.of(1, 2) println nums.flatMap { it -> cs }.force() // [a, b, a, b] println nums.flatMap { n -> Stream.of('a', 'b').map { c -> [c, n] } }.force() // [[a, 1], [b, 1], [a, 2], [b, 2]]
  • 82. Recap
  • 83. Thank-You! Stream implementation shown in these slides is available on: https://github.com/CodeJugalbandi/FunctionalProgramming/blob/master/melodies/lazy_sequences/Stream.groovy
  • 84. References Programming Groovy Venkat Subramaniam Groovy In Action Dierk König Structure and Interpretation of Computer Programs Abelson, Sussman and Sussman Functional Prog. Coursera Course Martin Odersky Functional Prog. with Groovy Arturo Herrero On Understanding Types, Data Abstraction & Polymorphism Luca Cardelli, Peter Wegner