(defrecord Assistant [name id])
(updatePersonalInfo )
Manager:
(defrecord Manager [name id employees])
(raise )
(extend-type Assistant Employee
(roles [this] "assistant"))
(extend-type Manager Employee
(roles [this] (str "manager of " (count employees))))
85
The Expression Problem
86
The Expression Problem
Add a new
data type
Add a new
operation
Without changing:
- Existing data types
- Existing operations
87
The Expression Problem
Add Employee
Add raise()
Without changing:
- Assistant
6. edn characteristics
edn ⊇ Clojure syntax
used by Datomic and others as data transfer format
language/implementation neutral
edn is a system for the conveyance of values.
6
7. edn is a system for the conveyance of values.
a type system
NOT:
schema based
a system for representing objects
7
8. Scalars
nil
nil, null, or nothing
booleans
true or false
strings
enclosed in “double quotes”
may span multiple lines
t r n supported
characters
c
newline, return, space and tab
8
10. Names
symbols
used to represent identifiers
should map to something other than strings
may include namespace prefixs:
my-namespace/foo
keywords
identifiers that designate themselves
semantically akin to enumeration values
symbols that must start with :
:fred or :my/fred
10
11. Collections
lists
a sequence of values
zero or more elements within ()
(a b 42)
vectors
a sequence of values…
…that supports random access
zero or more elements within []
[a b 42]
11
12. Collections
maps
collection of key/value associations
every key should appear only once
unordered
zero or more elements within {}
{:a 1, "foo" :bar, [1 2 3] four}
sets
collection of unique values
unordered
heterogeneous
zero or more elements within #{}
#{a b [1 2 3]}
12
34. Sequences
Abstraction of traditional Lisp lists
(seq coll)
if collection is non-empty, return seq
object on it, else nil
(first seq)
returns the first element
(rest seq)
returns a sequence of the rest of the
elements
34
35. Laziness
Most of the core library functions that produce
sequences do so lazily
e.g. map, filter etc
And thus if they consume sequences, do so
lazily as well
Avoids creating full intermediate results
Create only as much as you consume
Work with infinite sequences, datasets larger
than memory
35
45. Pervasive Destructuring
DSL for binding names
Works with abstract structure
Available wherever names are made*
Vector binding forms destructure sequential things
Map binding forms destructure associative things
45
46. Why Destructure?
without destructuring,
next-fib-pair is dominated
by code to “pick apart” pair
(defn next-fib-pair
[pair]
[(second pair) (+ (first pair) (second pair))])
(iterate next-fib-pair [0 1])
-> ([0 1] [1 1] [1 2] [2 3] [3 5] [5 8] [8 13]...)
destructure
it yourself…
46
47. Sequential Destructure
…or you can do the same
thing with a simple []
(defn next-fib-pair
[[a b]]
[b (+ a b)])
(iterate next-fib-pair [0 1])
-> ([0 1] [1 1] [1 2] [2 3] [3 5] [5 8] [8 13] ...)
47
48. Simple Things Inline
which makes next-fib-pair
so simple that you will
probably inline it away!
(defn fibs
[]
(map first
(iterate (fn [[a b]] [b (+ a b)]) [0 1])))
48
49. Associative Data
same problem as before:
code dominated by
picking apart person
(defn format-name
[person]
(str/join " " [(:salutation person)
(:first-name person)
(:last-name person)]))
(format-name
{:salutation "Mr." :first-name "John" :last-name "Doe"})
-> "Mr. John Doe"
49
51. The :keys Option
a common scenario:
parameter names and key
names are the same, so say
them only once
(defn format-name
[{:keys [salutation first-name last-name]}]
(str/join " " [salutation first-name last-name]))
(format-name
{:salutation "Mr." :first-name "John" :last-name "Doe"})
-> "Mr. John Doe"
51
52. Optional Keyword Args
not a language feature, simply a
consequence of variable arity fns
plus map destructuring
(defn game
[planet & {:keys [human-players computer-players]}]
(println "Total players: "
(+ human-players computer-players)))
(game "Mars” :human-players 1 :computer-players 2)
Total players: 3
52
59. all forms are created equal !
interpretation is everything
59
60. all forms are created equal !
form
syntax
example
function
list
(println "hello")
operator
list
(+ 1 2)
method call
list
(.trim " hello ")
import
list
(require 'mylib)
metadata
list
(with-meta obj m)
control flow
list
(when valid? (proceed))
scope
list
(dosync (alter ...))
60
72. From Maps...
(def stu {:fname "Stu"
:lname "Halloway"
:address {:street "200 N Mangum"
:city "Durham"
:state "NC"
:zip 27701}})
(:lname stu)
=> "Halloway"
(-> stu :address :city)
=> "Durham"
data oriented
keyword access
nested access
(assoc stu :fname "Stuart")
=> {:fname "Stuart", :lname "Halloway",
:address ...}
(update-in stu [:address :zip] inc)
=> {:address {:street "200 N Mangum",
:zip 27702 ...} ...}
update
nested
update
72
73. ...to Records!
(defrecord Person [fname lname address])
(defrecord Address [street city state zip])
(def stu (Person. "Stu" "Halloway"
(Address. "200 N Mangum"
"Durham"
"NC"
27701)))
still data-oriented:
(:lname stu)
=> "Halloway"
(-> stu :address :city)
=> "Durham"
object
oriented
type is there
when you
everything works
as before
care
(assoc stu :fname "Stuart")
=> :user.Person{:fname "Stuart", :lname"Halloway",
:address ...}
(update-in stu [:address :zip] inc)
=> :user.Person{:address {:street "200 N Mangum",
:zip 27702 ...} ...}
73
74. defrecord
named type
(defrecord Foo [a b c])
-> user.Foo
with slots
(def f (Foo. 1 2 3))
-> #'user/f
positional
constructor
(:b f)
-> 2
(class f)
-> user.Foo
keyword
access
plain ol'
casydht*
class
(supers (class f))
-> #{clojure.lang.IObj clojure.lang.IKeywordLookup java.util.Map
clojure.lang.IPersistentMap clojure.lang.IMeta java.lang.Object
java.lang.Iterable clojure.lang.ILookup clojure.lang.Seqable
clojure.lang.Counted clojure.lang.IPersistentCollection
clojure.lang.Associative}
*Clojure abstracts so you don't have to
74
76. Protocols
(defprotocol AProtocol
"A doc string for AProtocol abstraction"
(bar [a b] "bar docs")
(baz [a] "baz docs"))
Named set of generic functions
Polymorphic on type of first argument
No implementation
Define fns in the same namespaces as protocols
76
80. Extending to a Type
(baz "a")
java.lang.IllegalArgumentException:
No implementation of method: :baz
of protocol: #'user/AProtocol
found for class: java.lang.String
(extend-type String
AProtocol
(bar [s s2] (str s s2))
(baz [s] (str "baz " s)))
(baz "a")
=> "baz a"
80
81. Extending to Many Types
note extend
to nil
from Clojure
reducers.clj
81
96. Wrappers = Complexity
Ruin identity
Ruin Equality
Cause nonlocal defects
Don’t compose: AB + AC ≠ ABC
Have bad names
96
97. 3. Monkey Patching
strings are
java.util.Collection
sneak in
not
and change
collections
them!
java.util.List
String
common in e.g. ruby
not possible in java
97
98. Monkey Patching = Complexity
Preserves identity (mostly)
Ruins namespacing
Causes nonlocal defects
Forbidden in some languages
98
99. 4. Generic Functions (CLOS)
polymorphism
lives in the
fns
count
String
reduce
don't touch existing
implementation,
just use it
map
99
107. memory, the capacity ... for returning to a
previous state when the cause of the
transition from that state is removed
record, the fact or condition of having been
written down as evidence...
... an authentic or official report
107
108. Memory, Records = Places?
Memory is small and expensive
Storage is small and expensive
Machines are precious, dedicated resources
Applications are control centers
108
109. A Different Approach
New memories use new places
New records use new places
New moments use new places
“In-place” changes encapsulated by constructors
109
113. What Can Be a Value?
42
{:first-name "Stu",
:last-name "Halloway"}
113
114. What Can Be a Value?
42
{:first-name "Stu",
:last-name "Halloway"}
114
115. What Can Be a Value?
42
{:first-name "Stu",
:last-name "Halloway"}
115
116. What Can Be a Value?
42
{:first-name "Stu",
:last-name "Halloway"}
Anything?
116
117. References
Refer to values (or other references)
Permit atomic, functional succession
Model time and identity
Compatible with a wide variety of update semantics
117
130. Software Transactional Memory
Refs can change only within a transaction
Provides the ACI in ACID
Transactions are speculative, will be retried
130
132. Transactions
(defn transfer
[from to amount]
(dosync
(alter from - amount)
(alter to + amount)))
(alter from - 1)
=> IllegalStateException No transaction running
132
133. Transactions
(defn transfer
[from to amount]
(dosync
(alter from - amount)
(alter to + amount)))
scope transaction
(alter from - 1)
=> IllegalStateException No transaction running
133
134. Transactions
(defn transfer
[from to amount]
(dosync
(alter from - amount)
(alter to + amount)))
functional succession
(alter from - 1)
=> IllegalStateException No transaction running
134
135. Transactions
(defn transfer
[from to amount]
(dosync
(alter from - amount)
(alter to + amount)))
coordination
guaranteed!
(alter from - 1)
=> IllegalStateException No transaction running
135
136. STM Details
Uses locks, latches internally to avoid churn
Deadlock detection and barging
No read tracking
Readers never impede writers
Nobody impedes readers
136
138. Summary
Serious Lisp on the JVM
Built as a destination
Advanced language features
Advanced implementation
Secret weapon?
138
139. Clojure in the wild?
“We
re-coded our flagship application XXXXXX
from Java to Clojure about a year ago.
NEVER looked back. Why?
Reduced our lines of code down by at
least half.
Support and bugs have likewise been cut
by about 65-70%.
We have large enterprise clients.
How did we get Clojure into these very
old guard environments????
139
140. Between you and me.... we
lie.
We don't talk about Clojure.
We talk about "Java Extensions" or
"the Clojure Java Extension".
No one is the wiser.
Clients LOVE us for our blistering
fast turn around.
We present ourselves as a larger
company with fake Linkedin employees.
We actually only have 4 real
employees.
But with Clojure we do the same
work as if we had 20.”
140
141. ?’s
The preceding work is licensed under the Creative
Commons Attribution-Share Alike 3.0 License.
http://creativecommons.org/licenses/by-sa/3.0/us/
Clojure (inside out)
Neal Ford, Stuart Halloway
bit.ly/clojureinsideout
Functional Thinking
bit.ly/nf_ftvideo
Presentation Patterns
Neal Ford, Matthew McCullough, Nathaniel Schutta
http://presentationpatterns.com
141