About me
• Functional apprentice to Clojure
• Founder and co-leader of Warszawa JUG
• Conference organizer of Javarsovia, Confitura, warsjawa
• Member of NetBeans DreamTeam
• Blogger of http://JacekLaskowski.pl
• Blogger of http://blog.japila.pl
• @jaceklaskowski
• Member of Apache Software Foundation
• IBMer
Why should I care
about Clojure?
(map Clojure everyday-tasks)
Clojure for real-world, day-to-day programming
Functional language
• Functions are first-class citizens
• They’re like other values
• They can be
• passed to a function
• returned from a function
• HOF = higher-order function
Function definition
(fn [args]
(body)
(defn function-name [args]
(body))
#(body)
Fundamental functions
• map - apply a function to a sequence
• returns a sequence
• reduce - accumulation over a sequence
• returns an accumulator
• filter - filters items satisfying a predicate
• return a sequence
map function
Apply a function
(map f ‘(1 2 3)) to a sequence
and return a sequence
in which every item is
‘((f 1) (f 2) (f 3)) transformed by the
function
Examples: addVat, convertCurrency
http://cyrille.martraire.com/2011/03/thinking-functional-programming-with-map-and-fold-in-your-everyday-java/
reduce function
(reduce f ‘( 1 2 3 4 )) Accumulate
over a sequence
and
‘( f ( f ( f 1 2 ) 3 ) 4 ) return the accumulator
Mutation
• Persistent references to a mutable state
• Var - dynamically rebound on a per-
thread basis (thread isolation)
• Ref - transactional via Clojure STM
• Agent - independent, asynchronous
change of individual location
• Atom - synchronous, independent state
(def a (ref 0))
(def b (ref 0))
(alter a inc) ;; java.lang.IllegalStateException:
;; No transaction running
(dosync
(alter a inc)
(alter b inc))
(def a (ref 0))
(def b (ref 0))
(alter a inc) ;; java.lang.IllegalStateException:
;; No transaction running
(dosync
(alter a inc)
(alter b inc))
user=> 1
explicit about mutation
(def a (ref 0))
(def b (ref 0))
(alter a inc) ;; java.lang.IllegalStateException:
;; No transaction running
(dosync
(alter a inc)
(alter b inc))
user=> 1
(def c (agent 0))
(defn f-agt [v]
(Thread/sleep (* v 1000))
(println (Thread/currentThread))
(inc v))
(send c f-agt)
;; (agent-errors c)
;; (restart-agent c 0)
Namespace, Symbols
and Vars
• Symbol is a name bound to a Var
• (def v ...)
• Vars can be changed on a per-thread
basis
• Namespace is a map of symbols to Vars
• Namespace is similar to a fully-qualified
class name in Java
(import [javax.swing JFrame]
[java.awt.event ActionListener])
(def f (JFrame. "A window"))
(.setSize f 300 100)
(.setVisible f true)
(import [javax.swing JButton])
(def b (JButton. "Press me!"))
(.add f b)
(.pack f)
(.addActionListener b
(proxy [ActionListener] []
(actionPerformed [evt]
(println "I’ve been pressed"))))
Values in Clojure
• Strings are just instances of java.lang.String
user=> (.charAt “abc” 0)
• Numbers, characters, nil, true, false, and
keywords evaluate to themselves
user=> (Character/isLetter c)
Regular expressions
• #"pattern" - java.util.regex.Pattern
• (re-seq re s) lazy seq of matches of re in s
• (re-find m) the next regex match
• (re-matches re s) returns the match
• (re-matcher re s) gives j.u.regex.Matcher
• (re-groups m) returns the groups
AOT compilation
• Clojure compiles all code you load on-the-
fly into JVM bytecode
• Ahead-of-time (AOT) = before on-the-fly
at runtime
• Target of (compile) is namespace
• Each file, fn, and gen-class give new .class
AOT in Practice
• lein new [project-name]
• Add :main to project.clj
• lein uberjar
• java -jar [project-name-ver-standalone.jar]
Java EE web apps with Clojure
(Maven and Leiningen are there, too!)
http://blog.japila.pl/2012/03/java-ee-web-apps-with-clojure-maven-and-leiningen-are-there-too/
lein test
$ lein test
Copying 1 file to /Users/jacek/sandbox/hi/lib
Testing hi.test.core
FAIL in (replace-me) (core.clj:6)
No tests have been written.
expected: false
actual: false
Ran 1 tests containing 1 assertions.
1 failures, 0 errors.
lein test
$ lein test
Testing hi.test.core
Ran 1 tests containing 2 assertions.
0 failures, 0 errors.
Modern unit testing
• Midje - a TDD library for Clojure that
supports top-down ('mockish') TDD
• https://github.com/marick/Midje
• midje.sweet namespace
• fact macro
• (fact "one plus one is two"
(+ 1 1) => 2)
TDD with Midje #1
$ lein midje --lazytest
======================================
At #<Date Tue Feb 21 13:07:52 CET 2012>
Reloading librarian-clojure.run, librarian-clojure.repl, librarian-clojure.test.core, librarian-clojure.core,
librarian-clojure.books, librarian-clojure.db
FAIL at (core.clj:10)
Expected: 2
Actual: 3
FAIL at (core.clj:10)
Expected: 2
Actual: 3
FAILURE: 1 fact was not confirmed. (But 1 was.)
Done.
======================================
At #<Date Tue Feb 21 13:08:11 CET 2012>
Reloading librarian-clojure.test.core
All claimed facts (2) have been confirmed.
Done.
TDD with Midje #2
• (fact "doubles odd numbers"
(my-func 3) => 6)
• (fact "triples even numbers"
(my-func 4) => 12)
• A solution?
http://www.lispplusplus.com/2012/02/tdd-in-midje-in-nutshell.html