Slide 1

Slide 1 text

Ben Mabey Plain & Simple Clojure @bmabey Utah Java User’s Group, Aug 15 2013

Slide 2

Slide 2 text

redbrainlabs.com

Slide 3

Slide 3 text

"There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult." Tony Hoare, 1980 Turing Award Lecture

Slide 4

Slide 4 text

Clojure is a functional Lisp that targets the JVM and enables simpler software design.

Slide 5

Slide 5 text

Clojure is a functional Lisp that targets the JVM and enables simpler software design.

Slide 6

Slide 6 text

Read Eval Print Loop

Slide 7

Slide 7 text

Read Eval Print Loop ((Live))

Slide 8

Slide 8 text

Macros

Slide 9

Slide 9 text

(if (= code :RED) (do (launch-missiles!) (sound-the-alarm!)))

Slide 10

Slide 10 text

‘do’ implies side effects (if (= code :RED) (do (launch-missiles!) (sound-the-alarm!)))

Slide 11

Slide 11 text

(if (= code :RED) (do (launch-missiles!) (sound-the-alarm!))) (when (= code :RED) (launch-missiles!) (sound-the-alarm!))

Slide 12

Slide 12 text

(defmacro when "Evaluates test. If logical true, evaluates body in an implicit do." [test & body] (list 'if test (cons 'do body)))

Slide 13

Slide 13 text

(defmacro when "Evaluates test. If logical true, evaluates body in an implicit do." [test & body] (list 'if test (cons 'do body))) (macroexpand '(when (= code :RED) (launch-missiles!) (sound-the-alarm!)))

Slide 14

Slide 14 text

(defmacro when "Evaluates test. If logical true, evaluates body in an implicit do." [test & body] (list 'if test (cons 'do body))) (macroexpand '(when (= code :RED) (launch-missiles!) (sound-the-alarm!))) => (if (= code :RED) (do (launch-missiles!) (sound-the-alarm!)))

Slide 15

Slide 15 text

Paradigms as Libraries

Slide 16

Slide 16 text

Paradigms as Libraries Design by Contract a’la Eiffel - core.contracts

Slide 17

Slide 17 text

Paradigms as Libraries Design by Contract a’la Eiffel - core.contracts Logic Programming a’la Prolog - core.logic

Slide 18

Slide 18 text

Paradigms as Libraries Design by Contract a’la Eiffel - core.contracts Logic Programming a’la Prolog - core.logic Lightweight threads + channels a’la Go - core.async

Slide 19

Slide 19 text

Paradigms as Libraries Design by Contract a’la Eiffel - core.contracts Logic Programming a’la Prolog - core.logic Lightweight threads + channels a’la Go - core.async Optional/Gradual Type system - core.typed

Slide 20

Slide 20 text

Paradigms as Libraries Design by Contract a’la Eiffel - core.contracts Logic Programming a’la Prolog - core.logic Lightweight threads + channels a’la Go - core.async Optional/Gradual Type system - core.typed Actor model a’la Erlang - pulsar

Slide 21

Slide 21 text

Paradigms as Libraries Design by Contract a’la Eiffel - core.contracts Logic Programming a’la Prolog - core.logic Lightweight threads + channels a’la Go - core.async Optional/Gradual Type system - core.typed Actor model a’la Erlang - pulsar And more...

Slide 22

Slide 22 text

“If you give someone Fortran, he has Fortran. If you give someone Lisp, he has any language he pleases.” Guy Steele

Slide 23

Slide 23 text

Clojure is a functional Lisp that targets the JVM and enables simpler software design.

Slide 24

Slide 24 text

Constructor new Widget("gizmo"); (Widget. "gizmo")

Slide 25

Slide 25 text

Static Member Math.PI Math/PI

Slide 26

Slide 26 text

Instance Method string.trim(); (.trim string)

Slide 27

Slide 27 text

Chained Access person.getAddress().getState().getCode(); (.. person getAddress getState getCode)

Slide 28

Slide 28 text

Chained Access person.getAddress().getState().getCode(); (.. person getAddress getState getCode) Count ’em, 3 vs 1 pair!

Slide 29

Slide 29 text

Chained Access person.getAddress().getState().getCode(); (.. person getAddress getState getCode) (macroexpand '(.. person getAddress getState getCode)) (. (. (. person getAddress) getState) getCode)

Slide 30

Slide 30 text

Chained Access person.getAddress().getState().getCode(); (.. person getAddress getState getCode) (macroexpand '(.. person getAddress getState getCode)) (. (. (. person getAddress) getState) getCode) Clojure has parens so its Java doesn’t need to

Slide 31

Slide 31 text

Multiple Updates person.setFirstName("Ben"); person.setLastName("Mabey"); person.makePresenter(); (doto person (.setFirstName "Ben") (.setLastName "Mabey") .makePresenter)

Slide 32

Slide 32 text

Multiple Updates person.setFirstName("Ben"); person.setLastName("Mabey"); person.makePresenter(); (doto person (.setFirstName "Ben") (.setLastName "Mabey") .makePresenter) ‘person’ is implicit to method calls

Slide 33

Slide 33 text

Multiple Updates person.setFirstName("Ben"); person.setLastName("Mabey"); person.makePresenter(); (doto person (.setFirstName "Ben") (.setLastName "Mabey") .makePresenter) Again, ‘do’ signifies side effects

Slide 34

Slide 34 text

Implementing Interfaces new Runnable() { public void run() { System.out.println("Hello World"); } }; (reify Runnable (run [] (println "Hello")))

Slide 35

Slide 35 text

Clojure is a functional Lisp that targets the JVM and enables simpler software design.

Slide 36

Slide 36 text

Functional

Slide 37

Slide 37 text

Functional Programming with Values

Slide 38

Slide 38 text

Functional Programming with Values First Class Functions

Slide 39

Slide 39 text

Functional Programming with Values First Class Functions Laziness

Slide 40

Slide 40 text

Functional Programming with Values First Class Functions Laziness

Slide 41

Slide 41 text

public static int square(int x) { return x * x; }

Slide 42

Slide 42 text

public static int square(int x) { return x * x; } Value

Slide 43

Slide 43 text

public static int square(int x) { return x * x; } Value }Pure Function

Slide 44

Slide 44 text

public static int square(int x) { return x * x; } import java.util.Date; public static Date oneYearFrom(Date date) { date.setYear(date.getYear()+1); return date; }

Slide 45

Slide 45 text

public static int square(int x) { return x * x; } import java.util.Date; public static Date oneYearFrom(Date date) { date.setYear(date.getYear()+1); return date; } Reference Object

Slide 46

Slide 46 text

public static int square(int x) { return x * x; } import java.util.Date; public static Date oneYearFrom(Date date) { date.setYear(date.getYear()+1); return date; } Reference Object Mutable! Impure Function with side effects

Slide 47

Slide 47 text

public static int square(int x) { return x * x; } import java.util.Date; public static Date oneYearFrom(Date date) { date.setYear(date.getYear()+1); return date; } import org.joda.time.DateTime; public static DateTime oneYearFrom(DateTime date) { MutableDateTime temp = new MutableDateTime(date); temp.addYears(1); return temp.toDateTime(); }

Slide 48

Slide 48 text

public static int square(int x) { return x * x; } import java.util.Date; public static Date oneYearFrom(Date date) { date.setYear(date.getYear()+1); return date; } import org.joda.time.DateTime; public static DateTime oneYearFrom(DateTime date) { MutableDateTime temp = new MutableDateTime(date); temp.addYears(1); return temp.toDateTime(); } Value Object

Slide 49

Slide 49 text

public static int square(int x) { return x * x; } import java.util.Date; public static Date oneYearFrom(Date date) { date.setYear(date.getYear()+1); return date; } import org.joda.time.DateTime; public static DateTime oneYearFrom(DateTime date) { MutableDateTime temp = new MutableDateTime(date); temp.addYears(1); return temp.toDateTime(); } Value Object Pure Function

Slide 50

Slide 50 text

public static int square(int x) { return x * x; } import java.util.Date; public static Date oneYearFrom(Date date) { date.setYear(date.getYear()+1); return date; } import org.joda.time.DateTime; public static DateTime oneYearFrom(DateTime date) { //MutableDateTime temp = new MutableDateTime(date); //temp.addYears(1); return date.plusYears(1); } Pure Function Nice Immutable API

Slide 51

Slide 51 text

public static int square(int x) { return x * x; } import java.util.Date; public static Date oneYearFrom(Date date) { date.setYear(date.getYear()+1); return date; } import org.joda.time.DateTime; public static DateTime oneYearFrom(DateTime date) { //MutableDateTime temp = new MutableDateTime(date); //temp.addYears(1); return date.plusYears(1); }

Slide 52

Slide 52 text

public static int square(int x) { return x * x; } import java.util.Date; public static Date oneYearFrom(Date date) { date.setYear(date.getYear()+1); return date; } import org.joda.time.DateTime; public static DateTime oneYearFrom(DateTime date) { //MutableDateTime temp = new MutableDateTime(date); //temp.addYears(1); return date.plusYears(1); }

Slide 53

Slide 53 text

References Values

Slide 54

Slide 54 text

References Values primitives java.lang wrappers (Boolean, Byte, Character, Double, Float, Integer, Long, Short, String) other wrappers... e.g. UUID, URL, URI

Slide 55

Slide 55 text

References Values primitives java.lang wrappers (Boolean, Byte, Character, Double, Float, Integer, Long, Short, String) other wrappers... e.g. UUID, URL, URI Date BigInteger,BigDecimal, etc.

Slide 56

Slide 56 text

References Values primitives java.lang wrappers (Boolean, Byte, Character, Double, Float, Integer, Long, Short, String) other wrappers... e.g. UUID, URL, URI Date BigInteger,BigDecimal, etc. Collections ArrayList,ArrayDeque,TreeSet, HashSet, TreeMap, HashMap, LinkedList,PriorityQueue,etc...

Slide 57

Slide 57 text

References Values primitives java.lang wrappers (Boolean, Byte, Character, Double, Float, Integer, Long, Short, String) other wrappers... e.g. UUID, URL, URI Date BigInteger,BigDecimal, etc. Collections ArrayList,ArrayDeque,TreeSet, HashSet, TreeMap, HashMap, LinkedList,PriorityQueue,etc... Default for domain objects

Slide 58

Slide 58 text

References Values primitives java.lang wrappers (Boolean, Byte, Character, Double, Float, Integer, Long, Short, String) other wrappers... e.g. UUID, URL, URI Date BigInteger,BigDecimal, etc. Libraries joda-time, joda-money google-guava Collections ArrayList,ArrayDeque,TreeSet, HashSet, TreeMap, HashMap, LinkedList,PriorityQueue,etc... Default for domain objects

Slide 59

Slide 59 text

References Values primitives java.lang wrappers (Boolean, Byte, Character, Double, Float, Integer, Long, Short, String) other wrappers... e.g. UUID, URL, URI Date BigInteger,BigDecimal, etc. Libraries joda-time, joda-money google-guava Collections ArrayList,ArrayDeque,TreeSet, HashSet, TreeMap, HashMap, LinkedList,PriorityQueue,etc... Immutable Collections! Default for domain objects

Slide 60

Slide 60 text

References Values primitives java.lang wrappers (Boolean, Byte, Character, Double, Float, Integer, Long, Short, String) other wrappers... e.g. UUID, URL, URI Date BigInteger,BigDecimal, etc. Libraries joda-time, joda-money google-guava Collections ArrayList,ArrayDeque,TreeSet, HashSet, TreeMap, HashMap, LinkedList,PriorityQueue,etc... Immutable Collections! + They are values! Default for domain objects

Slide 61

Slide 61 text

References Values primitives java.lang wrappers (Boolean, Byte, Character, Double, Float, Integer, Long, Short, String) other wrappers... e.g. UUID, URL, URI Date BigInteger,BigDecimal, etc. Libraries joda-time, joda-money google-guava Collections ArrayList,ArrayDeque,TreeSet, HashSet, TreeMap, HashMap, LinkedList,PriorityQueue,etc... Immutable Collections! + They are values! - Copy on write (very good impls though) Default for domain objects

Slide 62

Slide 62 text

References Values primitives java.lang wrappers (Boolean, Byte, Character, Double, Float, Integer, Long, Short, String) other wrappers... e.g. UUID, URL, URI Date BigInteger,BigDecimal, etc. Libraries joda-time, joda-money google-guava Collections ArrayList,ArrayDeque,TreeSet, HashSet, TreeMap, HashMap, LinkedList,PriorityQueue,etc... Immutable Collections! + They are values! - Copy on write (very good impls though) - Can’t help with nesting Default for domain objects

Slide 63

Slide 63 text

References Values primitives java.lang wrappers (Boolean, Byte, Character, Double, Float, Integer, Long, Short, String) other wrappers... e.g. UUID, URL, URI Date BigInteger,BigDecimal, etc. Libraries joda-time, joda-money google-guava Collections ArrayList,ArrayDeque,TreeSet, HashSet, TreeMap, HashMap, LinkedList,PriorityQueue,etc... Immutable Collections! + They are values! - Copy on write (very good impls though) - Can’t help with nesting Default for domain objects

Slide 64

Slide 64 text

No content

Slide 65

Slide 65 text

“Best practice” but not idiomatic...

Slide 66

Slide 66 text

“Best practice” but not idiomatic... more difficult than it should be!

Slide 67

Slide 67 text

“Best practice” but not idiomatic... more difficult than it should be!

Slide 68

Slide 68 text

References Values

Slide 69

Slide 69 text

References Values primitives Java’s wrappers & libs

Slide 70

Slide 70 text

References Values primitives Java’s wrappers & libs Collections List, Vector, HashMap, TreeMap, ArrayMap, StructMap, Queue, HashSet, TreeSet, LazySeq, defrecords

Slide 71

Slide 71 text

Explicit Ref Types atom ref agent References Values primitives Java’s wrappers & libs Collections List, Vector, HashMap, TreeMap, ArrayMap, StructMap, Queue, HashSet, TreeSet, LazySeq, defrecords

Slide 72

Slide 72 text

Explicit Ref Types atom ref agent References Values primitives Java’s wrappers & libs Collections List, Vector, HashMap, TreeMap, ArrayMap, StructMap, Queue, HashSet, TreeSet, LazySeq, defrecords How Clojure addresses the non-functional aspect of programs, i.e. state.

Slide 73

Slide 73 text

Explicit Ref Types atom ref agent References Values primitives Java’s wrappers & libs Collections List, Vector, HashMap, TreeMap, ArrayMap, StructMap, Queue, HashSet, TreeSet, LazySeq, defrecords deftype

Slide 74

Slide 74 text

Explicit Ref Types atom ref agent References Values primitives Java’s wrappers & libs Collections List, Vector, HashMap, TreeMap, ArrayMap, StructMap, Queue, HashSet, TreeSet, LazySeq, defrecords Java libs for interop deftype

Slide 75

Slide 75 text

Explicit Ref Types atom ref Persistent Collections References Values primitives Java’s wrappers & libs Collections List, Vector, HashMap, TreeMap, ArrayMap, StructMap, Queue, HashSet, TreeSet, LazySeq, defrecords + They are values

Slide 76

Slide 76 text

Explicit Ref Types atom ref Persistent Collections References Values primitives Java’s wrappers & libs Collections List, Vector, HashMap, TreeMap, ArrayMap, StructMap, Queue, HashSet, TreeSet, LazySeq, defrecords + They are values + Structural Sharing + Memory efficient + Fast

Slide 77

Slide 77 text

Explicit Ref Types atom ref Persistent Collections References Values primitives Java’s wrappers & libs Collections List, Vector, HashMap, TreeMap, ArrayMap, StructMap, Queue, HashSet, TreeSet, LazySeq, defrecords + They are values + Structural Sharing + Memory efficient + Fast + Everything nests

Slide 78

Slide 78 text

Explicit Ref Types atom ref Persistent Collections References Values primitives Java’s wrappers & libs Collections List, Vector, HashMap, TreeMap, ArrayMap, StructMap, Queue, HashSet, TreeSet, LazySeq, defrecords + They are values + Structural Sharing + Memory efficient + Fast + Everything nests The rest of Clojure and its ecosystem is built on these!

Slide 79

Slide 79 text

Structural Sharing

Slide 80

Slide 80 text

Structural Sharing String brother = "brother"; String the = brother.substring(3, 6);

Slide 81

Slide 81 text

Structural Sharing String brother = "brother"; String the = brother.substring(3, 6); http://www.slreynolds.net/talks/clojure/collections/index.html

Slide 82

Slide 82 text

No content

Slide 83

Slide 83 text

Learn More http://www.slreynolds.net/talks/clojure/collections/index.html http://pragprog.com/magazines/2011-07/clojure-collections

Slide 84

Slide 84 text

http://www.innoq.com/blog/st/2010/04/clojure_performance_guarantees.html hash- map sorted- map hash- set sorted- set vector queue list lazy seq conj log32(n) log(n) log32(n) log(n) 1 1 1 1 assoc log32(n) log(n) log32(n) dissoc log32(n) log(n) disj log32(n) log(n) nth log32(n) n n n get log32(n) log(n) log32(n) log(n) log32(n) pop 1 1 1 1 peek 1 1 1 1 count 1 1 1 1 1 1 1 n TL;DR, they are fast

Slide 85

Slide 85 text

Transients

Slide 86

Slide 86 text

Transients MutableDateTime temp = new MutableDateTime(date); temp.addYears(1); return temp.toDateTime(); import org.joda.time.DateTime; public static DateTime oneYearFrom(DateTime date) { MutableDateTime temp = new MutableDateTime(date); temp.addYears(1); return temp.toDateTime(); }

Slide 87

Slide 87 text

Transients MutableDateTime temp = new MutableDateTime(date); temp.addYears(1); return temp.toDateTime(); import org.joda.time.DateTime; public static DateTime oneYearFrom(DateTime date) { MutableDateTime temp = new MutableDateTime(date); temp.addYears(1); return temp.toDateTime(); } (transient data) (persistent! transient-data)

Slide 88

Slide 88 text

Nesting

Slide 89

Slide 89 text

(def data {:nested [0 1 {:double "nested"}]}) Nesting

Slide 90

Slide 90 text

(def data {:nested [0 1 {:double "nested"}]}) (get-in data [:nested 2 :double]) Nesting

Slide 91

Slide 91 text

(def data {:nested [0 1 {:double "nested"}]}) (get-in data [:nested 2 :double]) Nesting First map key Index into vector Nested map key

Slide 92

Slide 92 text

(def data {:nested [0 1 {:double "nested"}]}) (get-in data [:nested 2 :double]) > "nested" Nesting

Slide 93

Slide 93 text

(update-in data [:nested 2 :double] upper-case) (get-in data [:nested 2 :double]) > "nested" (def data {:nested [0 1 {:double "nested"}]}) Nesting

Slide 94

Slide 94 text

(update-in data [:nested 2 :double] upper-case) (get-in data [:nested 2 :double]) > "nested" (def data {:nested [0 1 {:double "nested"}]}) Nesting Same path

Slide 95

Slide 95 text

(update-in data [:nested 2 :double] upper-case) (get-in data [:nested 2 :double]) > "nested" (def data {:nested [0 1 {:double "nested"}]}) Nesting Fn applied to nested value

Slide 96

Slide 96 text

(get-in data [:nested 2 :double]) > "nested" (def data {:nested [0 1 {:double "nested"}]}) Nesting (update-in data [:nested 2 :double] upper-case) > {:nested [0 1 {:double "NESTED"}]} Entire “updated” data is returned as a value

Slide 97

Slide 97 text

(def data {:nested [0 1 {:double "nested"}]}) (get-in data [:nested 2 :double]) > "nested" Nesting (update-in data [:nested 2 :double] upper-case) > {:nested [0 1 {:double "NESTED"}]} (assoc-in data [:nested 2 :another] "val")

Slide 98

Slide 98 text

(def data {:nested [0 1 {:double "nested"}]}) (get-in data [:nested 2 :double]) > "nested" Nesting (update-in data [:nested 2 :double] upper-case) > {:nested [0 1 {:double "NESTED"}]} (assoc-in data [:nested 2 :another] "val") New key

Slide 99

Slide 99 text

(def data {:nested [0 1 {:double "nested"}]}) (get-in data [:nested 2 :double]) > "nested" Nesting (update-in data [:nested 2 :double] upper-case) > {:nested [0 1 {:double "NESTED"}]} (assoc-in data [:nested 2 :another] "val") New value New key

Slide 100

Slide 100 text

(def data {:nested [0 1 {:double "nested"}]}) (get-in data [:nested 2 :double]) > "nested" Nesting (update-in data [:nested 2 :double] upper-case) > {:nested [0 1 {:double "NESTED"}]} (assoc-in data [:nested 2 :another] "val") > {:nested [0 1 {:double "nested" :another "val"}]}

Slide 101

Slide 101 text

(def data {:nested [0 1 {:double "nested"}]}) (get-in data [:nested 2 :double]) > "nested" Nesting (update-in data [:nested 2 :double] upper-case) > {:nested [0 1 {:double "NESTED"}]} (assoc-in data [:nested 2 :another] "val") > {:nested [0 1 {:double "nested" :another "val"}]} Imagine doing this in Java.

Slide 102

Slide 102 text

Clojure is a functional Lisp that targets the JVM and enables simpler software design.

Slide 103

Slide 103 text

Simpler?

Slide 104

Slide 104 text

Simpler? Simple Made Easy Rich Hickey http://www.infoq.com/presentations/Simple-Made-Easy

Slide 105

Slide 105 text

Simple != Easy

Slide 106

Slide 106 text

Easy

Slide 107

Slide 107 text

Easy ease < aise < adjacens lie near i.e. familiar, convenient, near to our skill set or current understanding

Slide 108

Slide 108 text

Easy ease < aise < adjacens lie near i.e. familiar, convenient, near to our skill set or current understanding always relative! opposite of hard

Slide 109

Slide 109 text

Simple

Slide 110

Slide 110 text

Simple sim - plex one fold/braid opposite of complex

Slide 111

Slide 111 text

Simple sim - plex one fold/braid opposite of complex

Slide 112

Slide 112 text

Simple sim - plex one fold/braid no interleaving! one concept, one dimension one role, but maybe multiple operations opposite of complex

Slide 113

Slide 113 text

Simple

Slide 114

Slide 114 text

Simple Complex

Slide 115

Slide 115 text

Complect To interleave, entwine, braid

Slide 116

Slide 116 text

http://tinyurl.com/candy-land-pdf

Slide 117

Slide 117 text

No content

Slide 118

Slide 118 text

No content

Slide 119

Slide 119 text

No content

Slide 120

Slide 120 text

How would you model the game state using objects?

Slide 121

Slide 121 text

No content

Slide 122

Slide 122 text

public class GameBoard { ! ! private List spaces = new ArrayList(); ! private CardDeck cardDeck = new CardDeck(); ! private List players = new ArrayList(); ! // Points to player whose turn it is next ! private int playerPointer = 0; ! // Players position on the board ! private Integer[] playerPositions; .... }

Slide 123

Slide 123 text

public class GameBoard { ! ! private List spaces = new ArrayList(); ! private CardDeck cardDeck = new CardDeck(); ! private List players = new ArrayList(); ! // Points to player whose turn it is next ! private int playerPointer = 0; ! // Players position on the board ! private Integer[] playerPositions; .... } public class Player { ! private String name; ! public Player(String name) { ! ! this.name = name; ! } ! public String getName() { ! ! return name; ! } }

Slide 124

Slide 124 text

No content

Slide 125

Slide 125 text

{:players [{:location 32 :name "ben"} {:location 14 :name "maren"}] :board [{:color :purple} ... {:color :orange, :shortcut-to 62} .... {:color :yellow, :picture :candy-heart} ...] :decks {:unplayed (:red [:orange :orange] :peppermint-stick ...) :played (:red :blue ...)}}

Slide 126

Slide 126 text

{:players [{:location 32 :name "ben"} {:location 14 :name "maren"}] :board [{:color :purple} ... {:color :orange, :shortcut-to 62} .... {:color :yellow, :picture :candy-heart} ...] :decks {:unplayed (:red [:orange :orange] :peppermint-stick ...) :played (:red :blue ...)}} Commas Optional

Slide 127

Slide 127 text

No content

Slide 128

Slide 128 text

distinct filter remove for keep keep-indexed cons concat lazy-cat mapcat cycle interleave interpose rest next fnext nnext drop drop-while nthnext for take take-nth take-while butlast drop-last for flatten reverse sort sort-by shuffle split-at split- with partition partition-all partition-by map pmap mapcat for replace reductions map-indexed seque first ffirst nfirst second nth when- first last rand-nth zipmap into reduce set vec into-array to-array-2d frequencies group-by apply not-empty some reduce seq? every? not- every? not-any? empty? some filter doseq dorun doall realized? assoc get get-in assoc-in update-in peek pop subvec conj cons into

Slide 129

Slide 129 text

It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures. Alan Perlis

Slide 130

Slide 130 text

No content

Slide 131

Slide 131 text

Data

Slide 132

Slide 132 text

Methods Data

Slide 133

Slide 133 text

( )

Slide 134

Slide 134 text

( ) Values

Slide 135

Slide 135 text

( ) Values Functions

Slide 136

Slide 136 text

Create a Game Board

Slide 137

Slide 137 text

Create a Game Board

Slide 138

Slide 138 text

Create a Game Board • 129 colored spaces • 6 colors in repeating sequence: 1. Purple 2.Yellow 3.Blue 4.Orange 5.Green 6.Red

Slide 139

Slide 139 text

Create a Game Board ! private static final int NUMBER_SPACES = 129; ! public static String[] COLOR_SEQUENCE = { ! ! "Purple", ! ! "Yellow", ! ! "Blue", ! ! "Orange", ! ! "Green", ! ! "Red" ! }; !

Slide 140

Slide 140 text

Create a Game Board ! private static final int NUMBER_SPACES = 129; ! public static String[] COLOR_SEQUENCE = { ! ! "Purple", ! ! "Yellow", ! ! "Blue", ! ! "Orange", ! ! "Green", ! ! "Red" ! }; ! ! public GameBoard() { ! ! // Create Spaces ! ! for (int i = 0; i < NUMBER_SPACES; i++) { ! ! ! String color = COLOR_SEQUENCE[i % COLOR_SEQUENCE.length]; ! ! ! spaces.add(new ColoredSpace(color)); ! ! } ! ! ... } ! !

Slide 141

Slide 141 text

(def colors [:purple :yellow :blue :orange :green :red])

Slide 142

Slide 142 text

(def colors [:purple :yellow :blue :orange :green :red]) user> (find-doc "cycle") ------------------------- clojure.core/check-cyclic-dependency ([path]) Detects .... ------------------------- clojure.core/cycle ([coll]) Returns a lazy (infinite!) sequence of repetitions of the items in coll. ProTip, use find-doc to search for fns

Slide 143

Slide 143 text

(def colors [:purple :yellow :blue :orange :green :red]) user> (find-doc "cycle") ------------------------- clojure.core/check-cyclic-dependency ([path]) Detects .... ------------------------- clojure.core/cycle ([coll]) Returns a lazy (infinite!) sequence of repetitions of the items in coll.

Slide 144

Slide 144 text

(def colors [:purple :yellow :blue :orange :green :red]) (cycle colors) => (:purple :yellow :blue :orange :green :red :purple :yellow :blue :orange ...)

Slide 145

Slide 145 text

(def colors [:purple :yellow :blue :orange :green :red]) (cycle colors) => (:purple :yellow :blue :orange :green :red :purple :yellow :blue :orange ...) (take 3 (cycle colors)) => (:purple :yellow :blue)

Slide 146

Slide 146 text

(def colors [:purple :yellow :blue :orange :green :red]) (cycle colors) => (:purple :yellow :blue :orange :green :red :purple :yellow :blue :orange ...) (take 3 (cycle colors)) => (:purple :yellow :blue) Laziness Increases Modularity

Slide 147

Slide 147 text

(def colors [:purple :yellow :blue :orange :green :red]) (cycle colors) => (:purple :yellow :blue :orange :green :red :purple :yellow :blue :orange ...) (take 3 (cycle colors)) => (:purple :yellow :blue) Laziness Increases Modularity for (int i = 0; i < NUMBER_SPACES; i++) { ! ! ! String color = COLOR_SEQUENCE[i % COLOR_SEQUENCE.length]; ! ! ! spaces.add(new ColoredSpace(color)); ! ! }

Slide 148

Slide 148 text

(def colors [:purple :yellow :blue :orange :green :red]) (cycle colors) => (:purple :yellow :blue :orange :green :red :purple :yellow :blue :orange ...) (take 3 (cycle colors)) => (:purple :yellow :blue)

Slide 149

Slide 149 text

(def colors [:purple :yellow :blue :orange :green :red]) (cycle colors) => (:purple :yellow :blue :orange :green :red :purple :yellow :blue :orange ...) (take 3 (cycle colors)) => (:purple :yellow :blue) Inside-Out Code

Slide 150

Slide 150 text

(def colors [:purple :yellow :blue :orange :green :red]) (cycle colors) => (:purple :yellow :blue :orange :green :red :purple :yellow :blue :orange ...) (take 3 (cycle colors)) => (:purple :yellow :blue) Inside-Out Code (->> (cycle colors) (take 3)) => (:purple :yellow :blue) Threading Operators

Slide 151

Slide 151 text

(def colors [:purple :yellow :blue :orange :green :red]) (cycle colors) => (:purple :yellow :blue :orange :green :red :purple :yellow :blue :orange ...) (take 3 (cycle colors)) => (:purple :yellow :blue) (->> (cycle colors) (take 3)) => (:purple :yellow :blue)

Slide 152

Slide 152 text

(def colors [:purple :yellow :blue :orange :green :red]) (cycle colors) => (:purple :yellow :blue :orange :green :red :purple :yellow :blue :orange ...) (take 3 (cycle colors)) => (:purple :yellow :blue) (->> (cycle colors) (take 3)) => (:purple :yellow :blue) (defn make-space [color] {:color color})

Slide 153

Slide 153 text

(def colors [:purple :yellow :blue :orange :green :red]) (cycle colors) => (:purple :yellow :blue :orange :green :red :purple :yellow :blue :orange ...) (take 3 (cycle colors)) => (:purple :yellow :blue) (->> (cycle colors) (take 3)) => (:purple :yellow :blue) (defn make-space [color] {:color color}) (->> colors (map make-space) cycle (take 3)) => ({:color :purple} {:color :yellow} {:color :blue})

Slide 154

Slide 154 text

(def colors [:purple :yellow :blue :orange :green :red]) (cycle colors) => (:purple :yellow :blue :orange :green :red :purple :yellow :blue :orange ...) (take 3 (cycle colors)) => (:purple :yellow :blue) (->> (cycle colors) (take 3)) => (:purple :yellow :blue) (defn make-space [color] {:color color}) (->> colors (map make-space) cycle (take 3)) => ({:color :purple} {:color :yellow} {:color :blue}) Small fns can be inlined

Slide 155

Slide 155 text

(map make-space) (defn make-card [color] {:color color}) (->> colors (map make-space) cycle (take 3)) => ({:color :purple} {:color :yellow} {:color :blue}) (def colors [:purple :yellow :blue :orange :green :red]) (cycle colors) => (:purple :yellow :blue :orange :green :red :purple :yellow :blue :orange ...) (take 3 (cycle colors)) => (:purple :yellow :blue) (->> (cycle colors) (take 3)) => (:purple :yellow :blue) Small fns can be inlined (->> colors (map #(array-map :color %)) cycle (take 3))

Slide 156

Slide 156 text

(map make-space) (defn make-card [color] {:color color}) (->> colors (map make-space) cycle (take 3)) => ({:color :purple} {:color :yellow} {:color :blue}) (def colors [:purple :yellow :blue :orange :green :red]) (cycle colors) => (:purple :yellow :blue :orange :green :red :purple :yellow :blue :orange ...) (take 3 (cycle colors)) => (:purple :yellow :blue) (->> (cycle colors) (take 3)) => (:purple :yellow :blue) Small fns can be inlined (->> colors (map #(array-map :color %)) cycle (take 3)) % is the anonymous first param

Slide 157

Slide 157 text

(def game-board (->> [:purple :yellow :blue :orange :green :red] (map #(array-map :color %)) cycle (take 129))) ! public GameBoard() { ! ! // Create Spaces ! ! for (int i = 0; i < NUMBER_SPACES; i++) { ! ! ! String color = COLOR_SEQUENCE[i % COLOR_SEQUENCE.length]; ! ! ! spaces.add(new ColoredSpace(color)); ! ! } ! ! ... } ! ! Create a Game Board

Slide 158

Slide 158 text

Play the game

Slide 159

Slide 159 text

Play the game public class GameBoard { ! public void play() { ! ! while (nextTurn()); ! ! System.out.println(“The winning player is:” + players.get(playerPointer).getName()); ! }

Slide 160

Slide 160 text

! // Player pulls a card from the top of deck and moves player ! private boolean nextTurn() { ! ! // Player selects card from top of deck ! ! Card currCard = cardDeck.takeTopCard(); ! ! // If the game has ended, return now ! ! if (movePlayerOnBoard(currCard)) return false; ! ! // Next players turn ! ! playerPointer = (playerPointer + 1) % players.size(); ! ! // Game has not ended yet ! ! return true; ! } Play the game public class GameBoard { ! public void play() { ! ! while (nextTurn()); ! ! System.out.println(“The winning player is:” + players.get(playerPointer).getName()); ! } ! // Player pulls a card from the top of deck and moves player ! private boolean nextTurn() { ! ! // Player selects card from top of deck ! ! Card currCard = cardDeck.takeTopCard(); ! ! // If the game has ended, return now ! ! if (movePlayerOnBoard(currCard)) return false; ! ! // Next players turn ! ! playerPointer = (playerPointer + 1) % players.size(); ! ! // Game has not ended yet ! ! return true; ! }

Slide 161

Slide 161 text

! // Player pulls a card from the top of deck and moves player ! private boolean nextTurn() { ! ! // Player selects card from top of deck ! ! Card currCard = cardDeck.takeTopCard(); ! ! // If the game has ended, return now ! ! if (movePlayerOnBoard(currCard)) return false; ! ! // Next players turn ! ! playerPointer = (playerPointer + 1) % players.size(); ! ! // Game has not ended yet ! ! return true; ! } Play the game public class GameBoard { ! public void play() { ! ! while (nextTurn()); ! ! System.out.println(“The winning player is:” + players.get(playerPointer).getName()); ! } ! // Player pulls a card from the top of deck and moves player ! private boolean nextTurn() { ! ! // Player selects card from top of deck ! ! Card currCard = cardDeck.takeTopCard(); ! ! // If the game has ended, return now ! ! if (movePlayerOnBoard(currCard)) return false; ! ! // Next players turn ! ! playerPointer = (playerPointer + 1) % players.size(); ! ! // Game has not ended yet ! ! return true; ! } Reference Object Land

Slide 162

Slide 162 text

! // Player pulls a card from the top of deck and moves player ! private boolean nextTurn() { ! ! // Player selects card from top of deck ! ! Card currCard = cardDeck.takeTopCard(); ! ! // If the game has ended, return now ! ! if (movePlayerOnBoard(currCard)) return false; ! ! // Next players turn ! ! playerPointer = (playerPointer + 1) % players.size(); ! ! // Game has not ended yet ! ! return true; ! } Play the game public class GameBoard { ! public void play() { ! ! while (nextTurn()); ! ! System.out.println(“The winning player is:” + players.get(playerPointer).getName()); ! } ! // Player pulls a card from the top of deck and moves player ! private boolean nextTurn() { ! ! // Player selects card from top of deck ! ! Card currCard = cardDeck.takeTopCard(); ! ! // If the game has ended, return now ! ! if (movePlayerOnBoard(currCard)) return false; ! ! // Next players turn ! ! playerPointer = (playerPointer + 1) % players.size(); ! ! // Game has not ended yet ! ! return true; ! } Reference Object Land

Slide 163

Slide 163 text

(defn next-move "Takes the game forward one move by drawing a card for the current player and moving them accordingly." [game]

Slide 164

Slide 164 text

(defn next-move "Takes the game forward one move by drawing a card for the current player and moving them accordingly." [game] Docstring attached as metadata

Slide 165

Slide 165 text

(defn next-move "Takes the game forward one move by drawing a card for the current player and moving them accordingly." [game] (let [{:keys [decks board player-index players]} game

Slide 166

Slide 166 text

(defn next-move "Takes the game forward one move by drawing a card for the current player and moving them accordingly." [game] (let [{:keys [decks board player-index players]} game Bind the keys we need with desctructuring

Slide 167

Slide 167 text

(defn next-move "Takes the game forward one move by drawing a card for the current player and moving them accordingly." [game] (let [{:keys [decks board player-index players]} game player (get players player-index)

Slide 168

Slide 168 text

(defn next-move "Takes the game forward one move by drawing a card for the current player and moving them accordingly." [game] (let [{:keys [decks board player-index players]} game player (get players player-index) [card new-decks] (draw-card decks)

Slide 169

Slide 169 text

(defn next-move "Takes the game forward one move by drawing a card for the current player and moving them accordingly." [game] (let [{:keys [decks board player-index players]} game player (get players player-index) [card new-decks] (draw-card decks) Returns a value, pair of [card updated-decks]

Slide 170

Slide 170 text

(defn next-move "Takes the game forward one move by drawing a card for the current player and moving them accordingly." [game] (let [{:keys [decks board player-index players]} game player (get players player-index) [card new-decks] (draw-card decks) We destructure and bind the pair as we like

Slide 171

Slide 171 text

(defn next-move "Takes the game forward one move by drawing a card for the current player and moving them accordingly." [game] (let [{:keys [decks board player-index players]} game player (get players player-index) [card new-decks] (draw-card decks) players-next-location (next-space card board player)]

Slide 172

Slide 172 text

(defn next-move "Takes the game forward one move by drawing a card for the current player and moving them accordingly." [game] (let [{:keys [decks board player-index players]} game player (get players player-index) [card new-decks] (draw-card decks) players-next-location (next-space card board player)] (-> game (assoc :decks new-decks :player-index (-> player-index inc (mod (count players))))

Slide 173

Slide 173 text

(defn next-move "Takes the game forward one move by drawing a card for the current player and moving them accordingly." [game] (let [{:keys [decks board player-index players]} game player (get players player-index) [card new-decks] (draw-card decks) players-next-location (next-space card board player)] (-> game (assoc :decks new-decks :player-index (-> player-index inc (mod (count players)))) (assoc-in [:players player-index :location] players-next-location))))

Slide 174

Slide 174 text

(defn next-move "Takes the game forward one move by drawing a card for the current player and moving them accordingly." [game] (let [{:keys [decks board player-index players]} game player (get players player-index) [card new-decks] (draw-card decks) players-next-location (next-space card board player)] (-> game (assoc :decks new-decks :player-index (-> player-index inc (mod (count players)))) (assoc-in [:players player-index :location] players-next-location))))

Slide 175

Slide 175 text

Play the game (defn play [game] (->> (iterate next-move game) (filter game-over?) first))

Slide 176

Slide 176 text

(defn play [game] (filter game-over?) first)) Play the game (->> (iterate next-move game) Text

Slide 177

Slide 177 text

(defn play [game] (filter game-over?) first)) Play the game (->> (iterate next-move game) Text v1

Slide 178

Slide 178 text

(defn play [game] (filter game-over?) first)) Play the game (->> (iterate next-move game) Text v1 next-move v2

Slide 179

Slide 179 text

(defn play [game] (filter game-over?) first)) Play the game (->> (iterate next-move game) Text v1 next-move v2 v3 next-move

Slide 180

Slide 180 text

(defn play [game] (filter game-over?) first)) Play the game (->> (iterate next-move game) Text v1 next-move v2 v3 next-move next-move ...

Slide 181

Slide 181 text

(defn play [game] (filter game-over?) first)) Play the game (->> (iterate next-move game) Text v1 next-move v2 v3 next-move next-move ... (->> 1 (iterate inc) (take 5)) > (1 2 3 4 5)

Slide 182

Slide 182 text

Play the game (defn play [game] (->> (iterate next-move game) (filter game-over?) first)) (filter game-over?) first)) Predicate function

Slide 183

Slide 183 text

Play the game (defn play [game] (->> (iterate next-move game) (filter game-over?) first)) (filter game-over?) first)) Return the ended game value

Slide 184

Slide 184 text

Play the game (defn play [game] (->> (iterate next-move game) (filter game-over?) first)) public void play() { ! ! while (nextTurn()); ! ! System.out.println(“The winning player is:” + players.get(playerPointer).getName()); ! }

Slide 185

Slide 185 text

Play the game (defn play [game] (->> (iterate next-move game) (filter game-over?) first)) (->> (create-game ["Ben" "Maren"]) play winning-player :name (println "The winning player is:")) public void play() { ! ! while (nextTurn()); ! ! System.out.println(“The winning player is:” + players.get(playerPointer).getName()); ! }

Slide 186

Slide 186 text

Play the game (defn play [game] (->> (iterate next-move game) (filter game-over?) first)) (->> (create-game ["Ben" "Maren"]) play winning-player :name (println "The winning player is:")) public void play() { ! ! while (nextTurn()); ! ! System.out.println(“The winning player is:” + players.get(playerPointer).getName()); ! } Our first side effect!

Slide 187

Slide 187 text

No content

Slide 188

Slide 188 text

Data Methods

Slide 189

Slide 189 text

Data Methods References

Slide 190

Slide 190 text

( ) Values Functions

Slide 191

Slide 191 text

Put it on the Web!

Slide 192

Slide 192 text

{:players [{:location 32, :name "ben"} {:location 14, :name "maren"}] :board [{:color :purple} ... {:color :orange, :shortcut-to 62} .... {:color :yellow, :picture :candy-heart} ...], :decks {:unplayed (:red [:orange :orange] :peppermint-stick ...), :played (:red, :blue, ...)}, :began-at #inst "2013-08-08T07:29:30.134-00:00"}

Slide 193

Slide 193 text

{"players" : [ {"location" : 32,"name" : "ben"}, {"location" : 14,"name" : "maren"} ], "board" : [{"color" : "purple"}, ... {"color" : "orange","shortcut-to" : 62}, ... {"color" : "yellow","picture" : "candy-heart"} ... ], "decks" : { "unplayed" : [ "red", ["orange", "orange"], "peppermint-stick", ...], "played" : [ "red", "blue" ...] }, "began-at" : "2013-08-08T07:29:30Z"}

Slide 194

Slide 194 text

JSON JavaScript EDN Clojure

Slide 195

Slide 195 text

{:players [{:location 32, :name "ben"} {:location 14, :name "maren"}] :board [{:color :purple} ... {:color :orange, :shortcut-to 62} .... {:color :yellow, :picture :candy-heart} ...], :decks {:unplayed (:red [:orange :orange] :peppermint-stick ...), :played (:red, :blue, ...)}, :began-at #inst "2013-08-08T07:29:30.134-00:00"}

Slide 196

Slide 196 text

{:players [{:location 32, :name "ben"} {:location 14, :name "maren"}] :board [{:color :purple} ... {:color :orange, :shortcut-to 62} .... {:color :yellow, :picture :candy-heart} ...], :decks {:unplayed (:red [:orange :orange] :peppermint-stick ...), :played (:red, :blue, ...)}, :began-at #inst "2013-08-08T07:29:30.134-00:00"} Custom Tagged Literal

Slide 197

Slide 197 text

{:id 54321 :players [{:location 32 :name "ben"} {:location 14 :name "maren"}] :board [{:color :purple} ... {:color :orange, :shortcut-to 62} .... {:color :yellow, :picture :candy-heart} ...] :decks {:unplayed (:red [:orange :orange] :peppermint-stick ...) :played (:red :blue ...)} :began-at #inst "2013-08-08T07:29:30.134-00:00"}

Slide 198

Slide 198 text

( ) Values Functions

Slide 199

Slide 199 text

( ) Values Functions References

Slide 200

Slide 200 text

Game Reference

Slide 201

Slide 201 text

Game Reference (def game-ref (atom (create-game ...)))

Slide 202

Slide 202 text

Game Reference (def game-ref (atom (create-game ...))) Reference Constructor

Slide 203

Slide 203 text

Game Reference (def game-ref (atom (create-game ...))) Reference Constructor Initial Value

Slide 204

Slide 204 text

Game Reference (def game-ref (atom (create-game ...))) (swap! game-ref take-next-move) Atomic Succession

Slide 205

Slide 205 text

Game Reference (def game-ref (atom (create-game ...))) (swap! game-ref take-next-move) Atomic Succession Fn to apply the ref’s current value to

Slide 206

Slide 206 text

(swap! game-ref add-player "Carter") Game Reference (def game-ref (atom (create-game ...))) (swap! game-ref take-next-move) Additional args to fn

Slide 207

Slide 207 text

(swap! game-ref add-player "Carter") Game Reference (deref game-ref) => current-game-value (def game-ref (atom (create-game ...))) (swap! game-ref take-next-move)

Slide 208

Slide 208 text

(swap! game-ref add-player "Carter") Game Reference (deref game-ref) => current-game-value (def game-ref (atom (create-game ...))) (swap! game-ref take-next-move) Observers can deref to get current state

Slide 209

Slide 209 text

(swap! game-ref add-player "Carter") Game Reference (deref game-ref) => current-game-value (def game-ref (atom (create-game ...))) (swap! game-ref take-next-move) @game-ref => current-game-value Observers can deref to get current state

Slide 210

Slide 210 text

Clojure’s Time Model

Slide 211

Slide 211 text

Clojure’s Time Model State is the current value of an identity. v1

Slide 212

Slide 212 text

Clojure’s Time Model State is the current value of an identity. An identity is series of values over time. v1 v2 v3

Slide 213

Slide 213 text

Clojure’s Time Model State is the current value of an identity. An identity is series of values over time. A reference to an identity allows updates and reads to it. v1 v2 v3

Slide 214

Slide 214 text

Clojure’s Time Model State is the current value of an identity. An identity is series of values over time. A reference to an identity allows updates and reads to it. Values never change, the past never changes. v1 v2 v3

Slide 215

Slide 215 text

( ) Values Functions References Identity

Slide 216

Slide 216 text

Data Methods References Identity?

Slide 217

Slide 217 text

Add a new card type

Slide 218

Slide 218 text

(defn next-location [card board player] (let [spaces-after-player (->> board (drop (:location player))) next-color-id (find-index #(= (:color card) (:color %)))] (or next-color-id (:winning-location board))))

Slide 219

Slide 219 text

Picture cards Candy Heart Peppermint Stick Ginger Bread Gum Drop Peanut Brittle Lollypop Ice Cream

Slide 220

Slide 220 text

(defn next-location [card board player] (let [spaces-after-player (->> board (drop (:location player))) next-color-id (find-index #(= (:color card) (:color %)))] (or next-color-id (:winning-location board))))

Slide 221

Slide 221 text

(defprotocol Card (next-location [card board player] "Determines the next location of the player"))

Slide 222

Slide 222 text

(defrecord ColorCard [color] Card (next-location [_ board player] ....) (defrecord PictureCard [picture] Card (next-location [_ board player] (find-index #(= picture (:picture %)) board))) .... (defprotocol Card (next-location [card board player] "Determines the next location of the player"))

Slide 223

Slide 223 text

Protocols are not just another name for interfaces...

Slide 224

Slide 224 text

they allow you to add new abstractions to existing types

Slide 225

Slide 225 text

(ns abstraction-a) (defprotocol AbstractionA (foo [obj]))

Slide 226

Slide 226 text

(extend-protocol AbstractionA nil (foo [s] (str "foo-A!")) String (foo [s] (str "foo-A-" (.toUpperCase s)))) (ns abstraction-a) (defprotocol AbstractionA (foo [obj]))

Slide 227

Slide 227 text

(extend-protocol AbstractionA nil (foo [s] (str "foo-A!")) String (foo [s] (str "foo-A-" (.toUpperCase s)))) (ns abstraction-a) (defprotocol AbstractionA (foo [obj])) (in-ns 'user) (require '[abstraction-a :as a]) (a/foo "Bar") => "foo-A-BAR" (a/foo nil) => "foo-A!"

Slide 228

Slide 228 text

(extend-protocol AbstractionA nil (foo [s] (str "foo-A!")) String (foo [s] (str "foo-A-" (.toUpperCase s)))) (ns abstraction-a) (defprotocol AbstractionA (foo [obj])) (in-ns 'user) (require '[abstraction-a :as a]) (a/foo "Bar") => "foo-A-BAR" (a/foo nil) => "foo-A!" (ns abstraction-b) (defprotocol AbstractionB (foo [obj]))

Slide 229

Slide 229 text

(extend-protocol AbstractionA nil (foo [s] (str "foo-A!")) String (foo [s] (str "foo-A-" (.toUpperCase s)))) (ns abstraction-a) (defprotocol AbstractionA (foo [obj])) (in-ns 'user) (require '[abstraction-a :as a]) (a/foo "Bar") => "foo-A-BAR" (a/foo nil) => "foo-A!" (extend-protocol AbstractionB nil (foo [s] (str "foo-B!")) String (foo [s] (str "foo-B-" (.toLowerCase s)))) (ns abstraction-b) (defprotocol AbstractionB (foo [obj]))

Slide 230

Slide 230 text

(extend-protocol AbstractionA nil (foo [s] (str "foo-A!")) String (foo [s] (str "foo-A-" (.toUpperCase s)))) (ns abstraction-a) (defprotocol AbstractionA (foo [obj])) (in-ns 'user) (require '[abstraction-a :as a]) (a/foo "Bar") => "foo-A-BAR" (a/foo nil) => "foo-A!" (extend-protocol AbstractionB nil (foo [s] (str "foo-B!")) String (foo [s] (str "foo-B-" (.toLowerCase s)))) (ns abstraction-b) (defprotocol AbstractionB (foo [obj])) (in-ns 'user) (require '[abstraction-b :as b]) (b/foo "Bar") => "foo-B-bar" (b/foo nil) => "foo-B!"

Slide 231

Slide 231 text

(extend-protocol AbstractionA nil (foo [s] (str "foo-A!")) String (foo [s] (str "foo-A-" (.toUpperCase s)))) (ns abstraction-a) (defprotocol AbstractionA (foo [obj])) (in-ns 'user) (require '[abstraction-a :as a]) (a/foo "Bar") => "foo-A-BAR" (a/foo nil) => "foo-A!" (extend-protocol AbstractionB nil (foo [s] (str "foo-B!")) String (foo [s] (str "foo-B-" (.toLowerCase s)))) (ns abstraction-b) (defprotocol AbstractionB (foo [obj])) (in-ns 'user) (require '[abstraction-b :as b]) (b/foo "Bar") => "foo-B-bar" (b/foo nil) => "foo-B!" Polymorphic functions live in namespaces, not complected on Class

Slide 232

Slide 232 text

( ) Values Functions References Identity

Slide 233

Slide 233 text

( ) Values Functions References Namespaces Identity

Slide 234

Slide 234 text

( ) Values Functions References Namespaces Identity Polymorphism

Slide 235

Slide 235 text

Data Methods References Identity?

Slide 236

Slide 236 text

Data Methods References Namespace Identity?

Slide 237

Slide 237 text

Data Methods References Polymorphism Namespace Identity?

Slide 238

Slide 238 text

(->> (range 100000) (map inc) (reduce +))

Slide 239

Slide 239 text

(require '[clojure.core.reducers :as r]) (->> (range 100000) (r/map inc) (r/reduce +)) (->> (range 100000) (map inc) (reduce +))

Slide 240

Slide 240 text

(require '[clojure.core.reducers :as r]) (->> (range 100000) (r/map inc) (r/reduce +)) (->> (range 100000) (map inc) (reduce +)) Process sequences in parallel with ForkJoin

Slide 241

Slide 241 text

(require '[clojure.core.reducers :as r]) (->> (range 100000) (r/map inc) (r/reduce +)) (->> (range 100000) (map inc) (reduce +)) Process sequences in parallel with ForkJoin The same “what”, different “how”

Slide 242

Slide 242 text

(extend-protocol CollFold nil (coll-fold [coll n combinef reducef] (combinef)) Object (coll-fold [coll n combinef reducef] ;;can't fold, single reduce (reduce reducef (combinef) coll)) clojure.lang.IPersistentVector (coll-fold [v n combinef reducef] (foldvec v n combinef reducef)) clojure.lang.PersistentHashMap (coll-fold [m n combinef reducef] (.fold m n combinef reducef fjinvoke fjtask fjfork fjjoin)))

Slide 243

Slide 243 text

Parallel Collections

Slide 244

Slide 244 text

Birthday party fun!

Slide 245

Slide 245 text

It is bound to happen...

Slide 246

Slide 246 text

No content

Slide 247

Slide 247 text

No content

Slide 248

Slide 248 text

I don’t want to go back to the gum drops!

Slide 249

Slide 249 text

No content

Slide 250

Slide 250 text

I can remember what the game looked like, why can’t your program?!?

Slide 251

Slide 251 text

Clojure’s Time Model A reference to an identity allows updates and reads to it. Values never change, the past never changes. v1 v2 v3 State is the current value of an identity. An identity is series of values over time.

Slide 252

Slide 252 text

Clojure’s Time Model A reference to an identity allows updates and reads to it. Values never change, the past never changes. v1 v2 v3 State is the current value of an identity. An identity is series of values over time. Observers can remember the past

Slide 253

Slide 253 text

(defn shadow-ref "Returns a ref that contains the time - 1 value of the given ref. In other words, shawdow-ref contains the value of ref before the las update to it (e.g. swap!). " [ref] (let [shadow (atom nil)] (add-watch ref :shawdower (fn [_key _ref old-state _new-state] (reset! shadow old-state))) shadow)) (def old-game-ref (shadow-ref game-ref))

Slide 254

Slide 254 text

(defn undo-and-skip-card [game-ref old-game-ref] (let [alternate-reality (-> @old-game-ref skip-card take-next-move)] (reset! game-ref alternate-reality))) (defn shadow-ref "Returns a ref that contains the time - 1 value of the given ref. In other words, shawdow-ref contains the value of ref before the las update to it (e.g. swap!). " [ref] (let [shadow (atom nil)] (add-watch ref :shawdower (fn [_key _ref old-state _new-state] (reset! shadow old-state))) shadow)) (def old-game-ref (shadow-ref game-ref))

Slide 255

Slide 255 text

Clojure is a functional Lisp that targets the JVM and enables simpler software design.

Slide 256

Slide 256 text

How do you want to spend your complexity budget?

Slide 257

Slide 257 text

Tradeoffs

Slide 258

Slide 258 text

Tradeoffs Different way of thinking takes time.

Slide 259

Slide 259 text

Tradeoffs Different way of thinking takes time. Idiomatic Clojure is slower than idiomatic Java in micro benchmarks.

Slide 260

Slide 260 text

Tradeoffs Different way of thinking takes time. Idiomatic Clojure is slower than idiomatic Java in micro benchmarks. Not as much structure provided (e.g. no familiar class structure), easier to make a mess.

Slide 261

Slide 261 text

Tradeoffs Different way of thinking takes time. Idiomatic Clojure is slower than idiomatic Java in micro benchmarks. Not as much structure provided (e.g. no familiar class structure), easier to make a mess. Tool support. Not many great IDE plugins conveniently available.

Slide 262

Slide 262 text

Tradeoffs Different way of thinking takes time. Idiomatic Clojure is slower than idiomatic Java in micro benchmarks. Not as much structure provided (e.g. no familiar class structure), easier to make a mess. Tool support. Not many great IDE plugins conveniently available. Harder to hire for?

Slide 263

Slide 263 text

Tradeoffs Different way of thinking takes time. Idiomatic Clojure is slower than idiomatic Java in micro benchmarks. Not as much structure provided (e.g. no familiar class structure), easier to make a mess. Tool support. Not many great IDE plugins conveniently available. Harder to hire for?

Slide 264

Slide 264 text

Simplicity Ease Real Tradeoffs

Slide 265

Slide 265 text

Thank you! BenMabey.com github.com/bmabey @bmabey

Slide 266

Slide 266 text

( ) Free Read Watch Do Free clojure.org clojure.org/cheatsheet clojure-doc.org Tutorials clojuredocs.org Examples youtube.c/user/ClojureTV infoq.com/Clojure/presentations .com Free clojure.org clojure.org/cheatsheet clojure-doc.org Tutorials clojuredocs.org Examples youtube.c/user/ClojureTV infoq.com/Clojure/presentations Free clojure.org clojure.org/cheatsheet clojure-doc.org Tutorials clojuredocs.org Examples youtube.c/user/ClojureTV infoq.com/Clojure/presentations $ clojure.org clojure.org/cheatsheet clojure-doc.org Tutorials clojuredocs.org Examples $ Clojure/Conj clojure-conj.org Training clojure.com $ Clojure/Conj clojure-conj.org Training clojure.com $ Clojure/Conj clojure-conj.org Training clojure.com

Slide 267

Slide 267 text

Extra Slides

Slide 268

Slide 268 text

C# Async async void Go() { _button.IsEnabled = false; string[] urls = "clojure.org www.albahari.com/nutshell/ golang.org".Split(); int totalLength = 0; foreach (string url in urls) { var uri = new Uri ("http://" + url); byte[] data = await new WebClient().DownloadDataTaskAsync (uri); _results.Text += "Length of " + url + " is " + data.Length + totalLength += data.Length; } _results.Text += "Total length: " + totalLength; }

Slide 269

Slide 269 text

CSP in Go // Run the Web, Image, and Video searches concurrently, // and wait for all results. // No locks. No condition variables. No callbacks. func Google(query string) (results []Result) { c := make(chan Result) go func() { c <- Web(query) } () go func() { c <- Image(query) } () go func() { c <- Video(query) } () for i := 0; i < 3; i++ { result := <-c results = append(results, result) } return } // http://talks.golang.org/2012/concurrency.slide#46

Slide 270

Slide 270 text

Go in Clojure (use 'clojure.core.async) (defn google [query] (let [c (chan)] (go (>! c (! c (! c (

Slide 271

Slide 271 text

“APL is like a beautiful diamond - flawless, beautifully symmetrical. But you can't add anything to it. If you try to glue on another diamond, you don't get a bigger diamond. Lisp is like a ball of mud. Add more and it's still a ball of mud - it still looks like Lisp.” Joel Moses, 1970s

Slide 272

Slide 272 text

Its my ball of mud!

Slide 273

Slide 273 text

“I remain unenthusiastic about actors.” Rich Hickey

Slide 274

Slide 274 text

Erlang Actors in Clojure ;; http://puniverse.github.io/pulsar/ (use 'co.paralleluniverse.pulsar.core) (let [actor (spawn #(receive :abc "yes!" [:why? answer] answer :else "oy"))] (! actor [:why? "because!"]) (join actor)) ; => "because!"

Slide 275

Slide 275 text

Color # in Deck Red 6 Orange 4 Yellow 6 Green 4 Blue 6 Purple 4 Create a Card Deck

Slide 276

Slide 276 text

Create a Card Deck public class CardDeck { ! private Stack cards; ! private static final Map CARD_GROUPS; ! static { ! ! CARD_GROUPS = new HashMap(); ! ! CARD_GROUPS.put("Red", 4); ! ! CARD_GROUPS.put("Orange", 4); ! ! CARD_GROUPS.put("Yellow", 6); ! ! CARD_GROUPS.put("Green", 4); ! ! CARD_GROUPS.put("Blue", 6); ! ! CARD_GROUPS.put("Purple", 4); ! }

Slide 277

Slide 277 text

Create a Card Deck ! private void addCardsToDeck() { ! ! cards = new Stack(); ! ! // Add cards to deck based on color and number ! ! for (Map.Entry cardGroupEntry : CARD_GROUPS.entrySet()) { ! ! ! String color = cardGroupEntry.getKey(); ! ! ! int numCardsInGroup = cardGroupEntry.getValue(); ! ! ! for (int i = 0; i < numCardsInGroup; i++) { ! ! ! ! cards.push(new Card(color)); ! ! ! } ! ! } ! }

Slide 278

Slide 278 text

Create a Card Deck

Slide 279

Slide 279 text

Create a Card Deck (def card-counts {:red 6 :orange 4 :yellow 6

Slide 280

Slide 280 text

Create a Card Deck (def card-counts {:red 6 :orange 4 :yellow 6 :green 4 :blue 6 :purple 4})

Slide 281

Slide 281 text

Create a Card Deck (def card-counts {:red 6 :orange 4 :yellow 6 :green 4 :blue 6 :purple 4}) (repeat 3 :red) => (:red :red :red)

Slide 282

Slide 282 text

Create a Card Deck (def card-counts {:red 6 :orange 4 :yellow 6 :green 4 :blue 6 :purple 4}) (repeat 3 :red) => (:red :red :red) (map (fn [pair] (repeat (last pair) (first pair))) {:red 2 :blue 2})=> ((:red :red) (:blue :blue))

Slide 283

Slide 283 text

Create a Card Deck (def card-counts {:red 6 :orange 4 :yellow 6 :green 4 :blue 6 :purple 4}) (repeat 3 :red) => (:red :red :red) (map (fn [pair] (repeat (last pair) (first pair))) {:red 2 :blue 2})=> ((:red :red) (:blue :blue)) (map (fn [[face freq]] (repeat freq face)) {:red 2 :blue 2}) => ((:red :red) (:blue :blue))

Slide 284

Slide 284 text

Create a Card Deck (def card-counts {:red 6 :orange 4 :yellow 6 :green 4 :blue 6 :purple 4}) (repeat 3 :red) => (:red :red :red) (map (fn [pair] (repeat (last pair) (first pair))) {:red 2 :blue 2})=> ((:red :red) (:blue :blue)) (map (fn [[face freq]] (repeat freq face)) {:red 2 :blue 2}) => ((:red :red) (:blue :blue)) (mapcat (fn [[face freq]] (repeat freq face)) {:red 2 :blue 2}) => (:red :red :blue :blue)

Slide 285

Slide 285 text

Create a Card Deck (def card-counts {:red 6 :orange 4 :yellow 6 :green 4 :blue 6 :purple 4}) (repeat 3 :red) => (:red :red :red) (map (fn [pair] (repeat (last pair) (first pair))) {:red 2 :blue 2})=> ((:red :red) (:blue :blue)) (map (fn [[face freq]] (repeat freq face)) {:red 2 :blue 2}) => ((:red :red) (:blue :blue)) (mapcat (fn [[face freq]] (repeat freq face)) {:red 2 :blue 2}) => (:red :red :blue :blue) (defn create-deck [face-freqs]

Slide 286

Slide 286 text

Create a Card Deck (def card-counts {:red 6 :orange 4 :yellow 6 :green 4 :blue 6 :purple 4}) (repeat 3 :red) => (:red :red :red) (map (fn [pair] (repeat (last pair) (first pair))) {:red 2 :blue 2})=> ((:red :red) (:blue :blue)) (map (fn [[face freq]] (repeat freq face)) {:red 2 :blue 2}) => ((:red :red) (:blue :blue)) (mapcat (fn [[face freq]] (repeat freq face)) {:red 2 :blue 2}) => (:red :red :blue :blue) (defn create-deck [face-freqs] (mapcat (fn [[face freq]] (repeat freq face)) face-freqs))

Slide 287

Slide 287 text

Create a Card Deck (def card-counts {:red 6 :orange 4 :yellow 6 :green 4 :blue 6 :purple 4}) (repeat 3 :red) => (:red :red :red) (map (fn [pair] (repeat (last pair) (first pair))) {:red 2 :blue 2})=> ((:red :red) (:blue :blue)) (map (fn [[face freq]] (repeat freq face)) {:red 2 :blue 2}) => ((:red :red) (:blue :blue)) (mapcat (fn [[face freq]] (repeat freq face)) {:red 2 :blue 2}) => (:red :red :blue :blue) (defn create-deck [face-freqs] (mapcat (fn [[face freq]] (repeat freq face)) face-freqs)) (def deck

Slide 288

Slide 288 text

Create a Card Deck (def card-counts {:red 6 :orange 4 :yellow 6 :green 4 :blue 6 :purple 4}) (repeat 3 :red) => (:red :red :red) (map (fn [pair] (repeat (last pair) (first pair))) {:red 2 :blue 2})=> ((:red :red) (:blue :blue)) (map (fn [[face freq]] (repeat freq face)) {:red 2 :blue 2}) => ((:red :red) (:blue :blue)) (mapcat (fn [[face freq]] (repeat freq face)) {:red 2 :blue 2}) => (:red :red :blue :blue) (defn create-deck [face-freqs] (mapcat (fn [[face freq]] (repeat freq face)) face-freqs)) (def deck (create-deck card-counts))

Slide 289

Slide 289 text

Create a Card Deck ! private void addCardsToDeck() { ! ! cards = new Stack(); ! ! // Add cards to deck based on color and number ! ! for (Map.Entry cardGroupEntry : CARD_GROUPS.entrySet()) { ! ! ! String color = cardGroupEntry.getKey(); ! ! ! int numCardsInGroup = cardGroupEntry.getValue(); ! ! ! for (int i = 0; i < numCardsInGroup; i++) { ! ! ! ! cards.push(new Card(color)); ! ! ! } ! ! } ! }

Slide 290

Slide 290 text

Create a Card Deck ! private void addCardsToDeck() { ! ! cards = new Stack(); ! ! // Add cards to deck based on color and number ! ! for (Map.Entry cardGroupEntry : CARD_GROUPS.entrySet()) { ! ! ! String color = cardGroupEntry.getKey(); ! ! ! int numCardsInGroup = cardGroupEntry.getValue(); ! ! ! for (int i = 0; i < numCardsInGroup; i++) { ! ! ! ! cards.push(new Card(color)); ! ! ! } ! ! } ! } (defn create-deck [face-freqs] (mapcat (fn [[face freq]] (repeat freq face)) face-freqs))