2. Its a strange kind of love...
Clojure is very different
Part of your brain may rebel !!
Homo-Iconic
List based
Immutable state
Dynamically typed
Tiny syntax
Infinitely extensible
with Macros
3. What is Clojure
Functional programming on the JVM
A better Lisp ?
4. Why get functional ?
Clock speeds stopped getting faster around
2005
Cant get around the speed of silicon switches
Moores law still in effect
More cores added every 18 months
Laptops with 128 cores by 2020 ??
Concurrency at the hardware level
Not just multi-threading
6. Why a better Lisp ?
Clojure is easier to understand
Nicer libraries
Great interoperability with Java
platform
Closer to pure functional
language
Explicitly define mutable state
STM – transactional memory
8. Why create Clojure
Concurrency in Java / OO is challenging
Mutable state-full paradigm
Fast enough persistent data structures made it
viable
Functions as first class
Functions part of data structure
Functions do not have “side effects”
Focus on computation (maths) rather than
procedural algorithms
9. Why use Clojure
Its a pure functional programming language
You can use existing Java code and platform
Simple syntax
It gets you thinking differently !!!
An excuse to learn Emacs properly ??
18. We're not in Kansas any
more...
Java
package … ;
class …;
member variables;
access retType methodName (param, param) {…}
Clojure
(ns name-space-name)
(defstruct my-data-struture :label-name)
(functionName param (fn param))
; param's can be functions too !!
20. … a tree structure
Functions are data
Data structures are functions !!
21. Download
clojure.org
Or via buld tool
Maven
Leiningen
Cake
Java
At least version 5
Version 6 better
performance and
reporting
22. All hail the REPL
An interactive shell for clojure
Using Leiningen (Line – ing – en)
https://github.com/technomancy/leiningen/
lein
lein repl
23. Leiningen Clojure project
lein new
lein deps
lein repl
lein swank
Create a new clojure project
Download clojure
Start the interactive shell
Start repl server for emacs
24. Leiningen project file
(defproject my-jax-london-project "1.0.0-SNAPSHOT"
:description "A meaningful description"
:dependencies [[org.clojure/clojure "1.2.1"]
[org.clojure/clojure-contrib "1.2.0"]]
:dev-dependencies [[swank-clojure "1.2.1"]
[org.clojars.rayne/autodoc "0.8.0-
SNAPSHOT"]]
:autodoc { :name "London Clojure dojo", :page-title "Dojo API"}
;; Only re-fetch deps when they change in project.clj or when :library-path directory is empty.
:checksum-deps true
:license {:name "Eclipse Public License - v 1.0"
25. Loading code into the REPL
(load-file "temp.clj")
Stuff too big to type
use an absolute path or a path relative to
where you launched the REPL
Use Emacs or other IDE when you're ready
39. Overloading functions
(defn make
([ ] ; the make function that takes no arguments
(struct vector 0 0))
([x y] ; ... takes x and y keywords as arguments
(struct vector x y))
)
40. Pure functions – no side effects
Clojure functions are pure
they have no side effects
Unless you define them as such
Pure functions are easy to develop, test, and
understand
Aim for pure functions where possible
41. Clojure data structures
( Lists ) - Ordered collection of elements
(list 1 3 5) '(8 13 21)
{ map }
[ Vectors ] - Optimised for random access
[:tom :dick :harry]
Lists are for code, Vectors for data
(nth [:tom :dick :jane :harry ] 2)
42. List operations
(first 1 2 3)
The head of the list
(last 7 8 9)
The last element of the list
(rest 1 2 3 4 5)
Everything but the head
(cons :new-list '(1 2 3 4 5))
New list, given head and tail
43. More data structures...
(defstruct date :day :month :year)
(struct date)
as we did not specify any parameters, we just
get nil values
things in curly brackets are hash maps - the
usual Java hashmaps
44. maps
{ :a 1 :b 2}
user=> { :a 1 :b 2}
{:a 1, :b 2}
user=> { :a 1 :b }
java.lang.ArrayIndexOutOfB
oundsException: 3
user=> { :a 1 :b 2}
{:a 1, :b 2}
user=> { :a 1 :b 3} ; this
should make the repl
complain in clojure 1.2,
fine in 1.1
{:a 1, :b 3}
user=> {:a {:a 1}}
{:a {:a 1}}
user=> {{:a 1} :a}
{{:a 1} :a}
; idiom - put :a on the left
46. Your own data structures
Special forms
(def johnny {:first-name "John", :last-name
"Stevenson"})
(defstruct person :first-name :last-name)
(defrecord person [String :first-name String
:last-name] :allow-nulls false)
47. Memory use
Once all references to an immutable structure
disappears it can be garbage collected.
Loops that create intermittent structures are
garbage collected every turn of the loop.
;;Memory : 0
(let [a (range 50000)]) ;; Memory: "big" while
the let is "executing"
;;Memory : 0 -- no reference to a anymore !
48. macros
Define extensions to the language
Clojure only has 7 primitive functions
Everything else in the language is created with
macros
Allows the language to be extended easily
without changes to the compiler
49. Special forms
Recognized by the Clojure compiler and not
implemented in Clojure source code.
A relatively small number of special forms
New ones cannot be implemented
catch, def, do, dot ('.'), finally, fn, if, let, loop,
monitor-enter, monitor-exit, new, quote,
recur, set!, throw, try and var
50. if
user=> (doc if)
-------------------------
if
Special Form
Please see http://clojure.org/special_forms#if
nil
51. Sequences
Sequences are logical views of collections
Logical lists
Java collections, Clojure-specific collections,
strings, streams, directory structures and XML
trees.
New Clojure collections created efficiently
Creates a sort of branch (delta) in the data
structure tree
53. Software Transactional
Memory
Works like transactional databases
Provides safe, concurrent access to memory
Agents allow encapsulated access to mutable
resources
54. Sharing mutable data
Use mutable references to immutable data
Reference Types
synchronous access to multiple pieces of
shared data ("coordinated") by using STM
Atoms
synchronous access to a single piece of shared
data.
Agents
asynchronous access to a single piece of
shared data
55. Name-spaces
Define a namespace
(ns name-space-name)
Include namespace code
(use 'names-space-name)
Like a package statement in Java
56. Clojure Libraries
(use 'clojure.contrib.str-utils)
'
Dont treat the next thing as a function
Open source libraries - http://clojars.org/
57. Recursive functions
Functions that call
themselves
Fractal coding
Tail recursion
Avoids blowing the
heap
A trick as the JVM
does not support
tail recursion
directly :-(
58. Tail recursion
(defn factorial [x]
(if (= x 0)
1
(* x (factorial (- x 1))
)))
Dont blow your stack
!!
59. TDD with Clojure is nice
Clojure test
(deftest test-name
(is (= value (function params))) )
61. Working with Java
Java Classes
fullstop after class name
(JFrame. )
(Math/cos 3) ; static method call
Java methods
fullstop before method name
(.getContentPane frame) ;;method name first
(. frame getContentPane) ;;object first
63. Working with Java (2)
Clojure gives you clean, simple, direct access
to Java
call any Java API directly
(System/getProperties)
-> {java.runtime.name=Java(TM) SE Runtime
Environment
64. Calling Clojure from Java
Export the clojure to a .jar
Add the jar to the classpath
Import the library in your code
Call it like any other method
65. Errors are inevitable
In the REPL
(printStackTrace *e)
*e holds the last exception raised
Clojure exceptions are Java exceptions
66. Managing State in Immutable
world
Mutable data structures to share between
threads (Software Transactional Memory)
refs, vars, atoms, agents
No locks required for thread safe code, no
deadlocks or race conditions
Atomically apply changes
67. Mutable functions
Swap!
Name functions that have side effects with an
exclamation mark
Naming convention
69. Documentation
(doc function-name)
(javadoc class-name)
(defn function-name
“A meaningful
description of the
function”
params )
Show fn description
Show javadoc in
browser
Write documentation
for your own
functions
70. Example documentation
(doc str)
Use doc to print the documentation for str:
user=> (doc str)
-------------------------
clojure.core/str
([] [x] [x & ys])
With no args, returns the empty string. With one
arg x, returns x.toString(). (str nil) returns
the empty string. With more than one arg,
returns the concatenation of the str values
of the args.
Fully qualified
namespace
Arguments
Details
71. find-doc
(find-doc “reduce”)
user=> (find-doc "reduce" )
-------------------------
clojure/areduce
([a idx ret init expr])
Macro
... details ...
-------------------------
clojure/reduce
([f coll] [f val coll])
... details ...
Search for functions
you dont know
Keyword parameter
72. Autodoc
Generate a website for your API's
http://tomfaulhaber.github.com/auto
doc/
Add dependency to your build file
http://clojars.org/org.clojars.rayne/autodoc
lein deps
lein autodoc
73. Where next
Coding dojo – London / start your own
www.londonjavacommunity.co.uk
Books – Programming Clojure (Pragmatic)
Website – clojure.org dev.clojure.org
Full Disclojure
vimeo.com/channels/fulldisclojure
clojure.jr0cket.co.uk
99 problems in clojure
Clojure has a programmatic macro system which allows the compiler to be extended by user code
You can add your own language features with macros. Clojure itself is built out of macros such as defstruct:
(defstruct person :first-name :last-name)
If you need different semantics, write your own macro. If you want a variant of structs with strong typing and configurable null-checking for all fields, you can create your own defrecord macro, to be used like this:
(defrecord
person [String :first-name String :last-name]
:allow-nulls false)
This ability to reprogram the language from within the language is the unique advantage of Lisp. You will see facets of this idea described in various ways:
Lisp is homoiconic - Lisp code is just Lisp data. This makes it easy for programs to write other programs.
The whole language is there, all the time. Paul Graham’s essay “Revenge of the Nerds” explains why this is so powerful. http://www.paulgraham.com/icad.html
Lisp syntax also eliminates rules for operator precedence and associativity, with fully parenthesized expressions, there is no possible ambiguity
Hickey's primary interest was concurrency — he wanted the ability to write multi-threaded applications, but increasingly found the mutable, stateful paradigm of object oriented programming to be part of the problem
The idea of a functional Lisp integrated with a commercially accepted host platform just seemed like chocolate and peanut butter. Coming up with persistent data structures that were fast enough was the tipping point for my considering it viable.
functions as first-class objects, meaning that functions can be placed into data structures, passed as arguments to other functions, evaluated in comparisons, even returned as the return value of another function. Moreover, functions do not have "side effects" — the ability to modify program state or data. This paradigm focuses on computation in the mathematical sense, rather than procedural algorithms, and is a completely different approach to programming.
Clojure does provide persistent data structures For application developers, the most significant distinction is that Clojure defaults to making all data structures immutable
developers must use one of four special mutable structures that are explicitly designed to be shared between threads: refs, vars, atoms, and agents. Clojure uses software transactional memory (STM) to coordinate changing these mutable structures while keeping them in a consistent state, much like a transactional database. This model makes it considerably simpler to write thread-safe code than it is in object oriented languages. No locks are required, therefore there are no deadlocks or race conditions.
Throw away your knowledge about OO and try something different
The downside of Lisp’s simple, regular syntax, at least for beginners, is Lisp’s fixation on parentheses and on lists as the core data type. Clojure offers an interesting combination of features that makes Lisp more approachable for non-Lispers.
The downside of Lisp’s simple, regular syntax, at least for beginners, is Lisp’s fixation on parentheses and on lists as the core data type. Clojure offers an interesting combination of features that makes Lisp more approachable for non-Lispers.
The downside of Lisp’s simple, regular syntax, at least for beginners, is Lisp’s fixation on parentheses and on lists as the core data type. Clojure offers an interesting combination of features that makes Lisp more approachable for non-Lispers.
The downside of Lisp’s simple, regular syntax, at least for beginners, is Lisp’s fixation on parentheses and on lists as the core data type. Clojure offers an interesting combination of features that makes Lisp more approachable for non-Lispers.
The downside of Lisp’s simple, regular syntax, at least for beginners, is Lisp’s fixation on parentheses and on lists as the core data type. Clojure offers an interesting combination of features that makes Lisp more approachable for non-Lispers.
Note: prefix notation
What are the 7 primitive functions?
When you require a library named clojure.contrib.str-utils, Clojure looks for
a file named clojure/contrib/str-utils.clj on the CLASSPATH
To avoid having to use the namespace for your library, you have to use refer, like so - (refer 'examples/introduction)
The use function does both require refer, like so –
(use 'examples.introduction)
o force a library to reload:
(use :reload-all 'examples.introduction)
The :reload-all flag is useful if you are making changes and want to see results without restarting the REPL.
This is barfing because the evaluator has to keep around state for each call due to the expression (* x (factorial (- x 1))) . We need to make this function tail recursive.
recur can be thought of as the Clojure operator for looping. Think of it like a function call for the nearest enclosing let or function definition supplied with new variables. Naively we can switch over to using this by doing:
user> (defn factorial2 [x]
(if (= x 0)
1
(* x (recur (- x 1)))))
But this is a compile-time error (which in itself is pretty neat!).
java.lang.UnsupportedOperationException: Can only recur from tail position (NO_SOURCE_FILE:4)
An accumulator parameter is an extra parameter to a function that's used to gather intermediate parts of the calculation. If we do this, we can make sure that the recur call is in the tail position. Using an anonymous function we get:
(defn factorial3 [x]
((fn [x y]
(if (= x 0)
y
(recur (- x 1) (* x y)))) x 1))
Now when recur is used, it doesn't need to keep any of the previous stack frame around. This means we can finally calculate factorial 1000000, which begins with 282 and ends with lots of zeros!
Use doc to print the documentation for str:
user=> (doc str)
-------------------------
clojure.core/str
([] [x] [x & ys])
With no args, returns the empty string. With one arg x, returns
x.toString().
(str nil) returns the empty string.
With more than one arg, returns the concatenation of the str values of the args.
The first line of doc’s output contains the fully qualified name of the
function.
The next line contains the possible argument lists, generated directly from the code. (Some common argument names and their uses are explained in the sidebar on the following page.)
Finally, the remaining lines contain the function’s doc-string, if the function definition included one.