Developer Data Modeling Mistakes: From Postgres to NoSQL
A Dive Into Clojure
1. A dive into Clojure
Carlo Sciolla, Product Lead @ Backbase
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
2. Carlo Sciolla
Product Lead
http://skuro.tk
Amsterdam Clojurians
@skuro
http://www.backbase.com http://bit.ly/amsclj
About me
Next gen portal software for the Bank 2.0, a recent history of Alfresco
and ECM specialist, Meetup organizer.
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
3. Motivational a.k.a. the towel they forgot to bring
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
4. I've seen things you people wouldn't believe
Programming languages evolved throughout half a century. Paradigms
rose and faded, with OOP and Java™ now the de-facto standards.
Yet there’s more to programming than what objects have to offer.
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
5. * Single inheritance
* [Almost] everything is an Object
* Single dispatch
* Non-covariant generics
* Type erasures
* C-like syntax
* Frameworks composition
The standard package
There are a number of design choices behind the Java™ programming
languages, and the ecosystem around it, that are quickly taken for
granted. This effectively creates a horizon that can limit your sight.
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
6. A paradigm shift
f (x)
As much as they’ve disappeared from mainstream development,
they’re now regaining momentum. Functional languages such as Scala
and Clojure are getting the spots on.
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
7. macro let
?
cons monad
gensym trampoline
recur zipper
seq lambda
The rocky road to LISP
There are more than fifty years of history behind any modern Lisp, and
while most of them have greatly influenced other languages, there’s a
unique core bulk of concepts that only finds home in a Lisp.
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
8. “ Lisp is worth learning for the
profound enlightenment experience
you will have when you finally get it;
that experience will make you a
“”
better programmer for the rest of
your days
Eric S. Raymond
When you finally get it
The very idea that you have to get Lisp is fascinating. As a matter of
facts, every Lisp developer experienced a moment of illumination, after
which all those parens finally fit together.
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
9. Open the parens to never look at programs the same way
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
10. (defn hello [name]
(println (str “Hello, ” name “!”)))
Double rainbows
As much as it might seem gibberish at first sight, at its very core there’s
little to know about Lisp syntax. Clojure adds some syntactic sugar on
top of standard Lisp, but the basics are all there.
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
11. (defn hello [name]
(println (str “Hello, ” name “!”)))
function calls
Function calls
The first symbol after an open parenthesis is interpreted as the name of
the function to call, with all the other members passed as parameters.
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
12. user> (hello “World”)
(defn hello [name]
(println (str “Hello, ” name “!”)))
Evaluation strategy
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
13. user> (hello “World”)
(defn hello [name]
(println (str “Hello, ” name “!”)))
Evaluation strategy
Variables binding follow lexicographical order.
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
14. user> (hello “World”)
(defn hello [name]
(println (str “Hello, ” name “!”)))
first invocation
Evaluation strategy
Variables binding follows lexicographical order. Then start from the
innermost list.
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
15. user> (hello “World”)
(defn hello [name]
(println “Hello, World!”))
second invocation
Evaluation strategy
Variables binding follows lexicographical order. Then start from the
innermost list. Substitute it with its yielded value, then repeat.
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
16. user> (hello “World”)
Hello, World!
(defn hello [name]
nil)
done
Evaluation strategy
Variables binding follows lexicographical order. Then start from the
innermost list. Substitute it with its yielded value, then repeat. When we
have a single value, we’re done and can yield a result.
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
17. user> (hello “World”)
Hello, World! Read
nil
user>
Eval
Print
Read, Eval, Print Loop
You just saw the REPL in action. More than a simple function execution
tool, it’s
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
18. Whatʼs in a seq by any other interface it wouldn’t smell the same
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
19. clojure.core/seq
([coll])
Returns a seq on the collection.
If the collection is empty, returns nil.
(seq nil) returns nil. seq also works on
Strings, native Java arrays (of reference
types) and any objects that implement
Iterable.
Much more than a collection
A sequential access data structure, most of the Clojure standard library
functions are able to process a sequence.
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
20. (seq '(1 "test" :odd true)) => (1 "test" :odd true)
(seq [1 "test" :odd true]) => (1 "test" :odd true)
(seq {1 "test" :odd true}) => ([1 "test"] [:odd true])
(seq #{1 "test" :odd true}) => (1 :odd true "test")
(seq “test”) => (t e s t)
More than a collection
A sequential access data structure, most of the Clojure standard library
functions are able to process a sequence. Wrapping a collection in a
sequence is just one function call away.
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
21. (map identity [1 2 3 4]) ; (1 2 3 4)
(filter odd? ‘(1 2 3 4)) ; (1 3)
(reduce str “test”) ; “test”
Automatic conversion
You don’t even have to bother converting your data structure, as the
standard library will do that for you.
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
22. Immutability ‘cause Java beans give you gas
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
23. Horse horse = new Horse(14);
horse.getPosition();
??
t
On state and identity
When using a POJO to model an identity, you fail to keep time into
consideration. Mutable state makes it hard to reason about code
execution in a concurrent environment.
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
24. (let [x {:one 1}]
(assoc x :two 2)
(println x) ; {:one 1}
(println (assoc x :two 2))) ; {:one 1 :two 2}
Persistent data structures
In Clojure, data structures are immutable. There’s no “add to map”, you
rather have to create a new map from the previous one, plus one
element.
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
25. (defn letter-count [string]
(let [reduce-fn (fn [counts letter]
(let [count (or (counts letter) 0)]
(assoc counts letter (inc count))))]
(reduce reduce-fn {} string)))
Doing real work
Immutability doesn’t get in the way of solving programming problems. If
anything, it makes it easier to reason about execution!
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
26. user> (letter-count “Amsterdam”)
Doing real work
Immutability doesn’t get in the way of solving programming problems. If
anything, it makes it easier to reason about execution!
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
27. user> (letter-count “Amsterdam”)
(reduce-fn {} A)
Doing real work
Immutability doesn’t get in the way of solving programming problems. If
anything, it makes it easier to reason about execution!
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
28. user> (letter-count “Amsterdam”)
(reduce-fn {} A)
(reduce-fn {A 1} m)
Doing real work
Immutability doesn’t get in the way of solving programming problems. If
anything, it makes it easier to reason about execution!
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
29. user> (letter-count “Amsterdam”)
(reduce-fn {} A)
(reduce-fn {A 1} m)
(reduce-fn {A 1 m 1} s)
Doing real work
Immutability doesn’t get in the way of solving programming problems. If
anything, it makes it easier to reason about execution!
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
30. user> (letter-count “Amsterdam”)
(reduce-fn {} A)
(reduce-fn {A 1} m)
(reduce-fn {A 1 m 1} s)
(reduce-fn {A 1 m 1 s 1} t)
Doing real work
Immutability doesn’t get in the way of solving programming problems. If
anything, it makes it easier to reason about execution!
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
31. user> (letter-count “Amsterdam”)
(reduce-fn {} A)
(reduce-fn {A 1} m)
(reduce-fn {A 1 m 1} s)
(reduce-fn {A 1 m 1 s 1} t)
(reduce-fn {A 1 m 1 s 1 t 1} e)
Doing real work
Immutability doesn’t get in the way of solving programming problems. If
anything, it makes it easier to reason about execution!
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
32. user> (letter-count “Amsterdam”)
(reduce-fn {} A)
(reduce-fn {A 1} m)
(reduce-fn {A 1 m 1} s)
(reduce-fn {A 1 m 1 s 1} t)
(reduce-fn {A 1 m 1 s 1 t 1} e)
(reduce-fn {A 1 m 1 s 1 t 1 e 1} r)
Doing real work
Immutability doesn’t get in the way of solving programming problems. If
anything, it makes it easier to reason about execution!
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
33. user> (letter-count “Amsterdam”)
(reduce-fn {} A)
(reduce-fn {A 1} m)
(reduce-fn {A 1 m 1} s)
(reduce-fn {A 1 m 1 s 1} t)
(reduce-fn {A 1 m 1 s 1 t 1} e)
(reduce-fn {A 1 m 1 s 1 t 1 e 1} r)
(reduce-fn {A 1 m 1 s 1 t 1 e 1 r 1} d)
Doing real work
Immutability doesn’t get in the way of solving programming problems. If
anything, it makes it easier to reason about execution!
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
34. user> (letter-count “Amsterdam”)
(reduce-fn {} A)
(reduce-fn {A 1} m)
(reduce-fn {A 1 m 1} s)
(reduce-fn {A 1 m 1 s 1} t)
(reduce-fn {A 1 m 1 s 1 t 1} e)
(reduce-fn {A 1 m 1 s 1 t 1 e 1} r)
(reduce-fn {A 1 m 1 s 1 t 1 e 1 r 1} d)
(reduce-fn {A 1 m 1 s 1 t 1 e 1 r 1 d 1} a)
Doing real work
Immutability doesn’t get in the way of solving programming problems. If
anything, it makes it easier to reason about execution!
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
35. user> (letter-count “Amsterdam”)
(reduce-fn {} A)
(reduce-fn {A 1} m)
(reduce-fn {A 1 m 1} s)
(reduce-fn {A 1 m 1 s 1} t)
(reduce-fn {A 1 m 1 s 1 t 1} e)
(reduce-fn {A 1 m 1 s 1 t 1 e 1} r)
(reduce-fn {A 1 m 1 s 1 t 1 e 1 r 1} d)
(reduce-fn {A 1 m 1 s 1 t 1 e 1 r 1 d 1} a)
(reduce-fn {A 1 m 1 s 1 t 1 e 1 r 1 d 1 a 1} m)
Doing real work
Immutability doesn’t get in the way of solving programming problems. If
anything, it makes it easier to reason about execution!
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
36. user> (letter-count “Amsterdam”)
(reduce-fn {} A)
(reduce-fn {A 1} m)
(reduce-fn {A 1 m 1} s)
(reduce-fn {A 1 m 1 s 1} t)
(reduce-fn {A 1 m 1 s 1 t 1} e)
(reduce-fn {A 1 m 1 s 1 t 1 e 1} r)
(reduce-fn {A 1 m 1 s 1 t 1 e 1 r 1} d)
(reduce-fn {A 1 m 1 s 1 t 1 e 1 r 1 d 1} a)
(reduce-fn {A 1 m 1 s 1 t 1 e 1 r 1 d 1 a 1} m)
{A 1 m 2 s 1 t 1 e 1 r 1 d 1 a 1}
Doing real work
Immutability doesn’t get in the way of solving programming problems. If
anything, it makes it easier to reason about execution!
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
37. sync coord
clojure.core/ref
([x] [x & options])
clojure.core/atom
([x] [x & options])
clojure.core/agent
([state & options])
Software transactional memory
When shared mutable state is really required, Clojure offers a number
of constructs to handle it in a inherently thread safe manner, which
frees you from resource locking.
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
38. Macro advantage
let your code write itself
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
39. (defn unless
“Executes body only if pred is false”
[pred body]
(if (not pred)
body)
user code
(unless (odd? 11) (println “woot?”))
(unless (odd? 12) (println “woot?”))
The classic example
Can you tell what’s wrong with this code?
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
40. (unless (odd? 11) (println “woot?”))
=> “woot?”
(unless (odd? 12) (println “woot?”))
=> “woot?”
Eager evaluation kills it
When implementing unless as a function, its arguments are evaluated
before unless itself is executed. This effectively prevents you from
getting it right.
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
41. (defmacro unless
[pred body]
(list 'if (list 'not pred)
body))
Macros FTW
Macros look like functions, but are treated in a slightly different way:
their arguments are passed unevaluated, and they’re supposed to
return code!
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
42. (macroexpand '(unless (odd? 12) (println "woot?")))
=>
(if (not (odd? 12))
(println "woot?"))
Reflection on steroids
You can inspect your macro with macroexpand and macroexpand-1.
The result now looks good: treating code as data, we can shuffle all the
pieces and put them in the order we want. This is LISP.
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
43. (defmacro unless
[pred body]
`(if (not ~pred)
~body))
Syntactic sugar
The syntax quote reader macro helps you write macros, as you end up
writing a “template” for the code you want to generate.
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
44. ; automatic resource freeing
(with-open [f (java.io.FileInputStream. "foo.txt")]
(loop [c (.read f)]
(when (not (= -1 c))
(println (char c))
(recur (.read f)))))
; threading macro
(-> c
char
println)
Programmable programming language
Macros are a powerful tool, and with great power comes great
responsibility: use with care. That said, macros alone puts the whole
concept of DSL just a built in of the language.
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
45. Lazy as a sloth when you ain’t gonna need it all
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
46. List<Integer> allInts = new ArrayList<Integer>();
for (Integer i = 0; ; ++i) {
allInts.add(i);
}
Infinite sequences
In presence of strict (eager) evaluation, a collection of infinite elements
will blow up your heap.
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
47. (defn all-ints [from]
(cons from (lazy-seq (all-ints (inc from)))))
(take 10 (all-ints 0))
=> (0 1 2 3 4 5 6 7 8 9)
Lazy sequences to the rescue
A call to lazy-seq will put evaluation on hold, so that only the requested
elements are “realized”. Also on the plus side, if you don’t hold a
reference on the head the unused elements are garbage collected!
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
48. (with-open [session (hibernate-session)]
(let [names [“carlo” “thomas” “luca” “nol”]
results (map #(find-user % session) names)]
(reset! users results))
(take 1 @users)
; org.hibernate.SessionException: Session was already closed
The upsides and the flipside
Most of the Clojure sequence library is made of lazy functions. While
this is handy in most cases, you must be aware of what’s lazy in your
code, as you might have to force the full realization of a seq.
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
49. user=> (doc doall)
-------------------------
clojure.core/doall
([coll] [n coll])
When lazy sequences are produced via functions that have side
effects, any effects other than those needed to produce the first
element in the seq do not occur until the seq is consumed. doall can
be used to force any effects. Walks through the successive nexts of
the seq, retains the head and returns it, thus causing the entire
seq to reside in memory at one time.
The programmer in control
You can choose whether is nice to have a lazy sequence, and when it’s
best to have all the elements available at once.
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
50. Whatʼs next
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
51. * http://clojure.org
* ClojureScript
* Overtone
* core-logic
* http://4clojure.com
* #clojure on Freenode
Some drops in the sea
Despite being so young a language, the Clojure ecosystem is already
huge. These are only a few ideas on where to start if you want to learn
more about Clojure.
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
52. April 18th
Amsterdam Clojurians
http://bit.ly/amsclj hosted by:
Always open for business
In two and a half year, we never missed a meetup. Come along and
enjoy the Dutch Clojure community!
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
53. Q/A
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012
54. http://imgs.xkcd.com/comics/lisp.jpg
Thanks
@skuro
http://skuro.tk
http://www.backbase.com
A DIVE INTO CLOJURE | April 6, 2012 | @skuro
Friday, April 6, 2012