Cracking clojure

73

Click here to load reader

description

Maybe you've heard of Clojure, one of those new-fangled JVM languages. How does anybody get any work done in a language like that? What's up with all those parentheses?If you're coming from Java and OOP, Clojure can indeed feel disorienting. In this talk we'll demystify the basics of Clojure and dissect the source of its power. Functional programming is on the rise and Clojure is indeed a functional language, but we'll learn the real secret sauce that makes cooking with Clojure fun.We'll look at how to translate concepts you know in Java (like domain objects, interfaces, collections, and concurrency) into their natural Clojure equivalents. And more importantly, we'll learn how these components interact to make Clojure a beautiful language for building abstractions.No prior knowledge of Clojure or functional programming is assumed... Clojure novices welcome!

Transcript of Cracking clojure

Page 1: Cracking clojure

Cracking ClojureAlex MillerRevelytix

Page 2: Cracking clojure

Clojure• A Lisp on the JVM (also ClojureScript on JavaScript)

• Dynamic (types, code, etc)• Functional language• Compiled (there is no interpreter)• Immutability and state management• Code is data • REPL - Read / Eval / Print / Loop• Interactive development

2

Page 3: Cracking clojure

It looks like this...

3

(defn neighbors [[x y]] (for [dx [-1 0 1] dy (if (zero? dx) [-1 1] [-1 0 1])] [(+ dx x) (+ dy y)]))

(defn live [n alive?] (or (= n 3) (and (= n 2) alive?)))

(defn step [world] (set (for [[cell n] (frequencies (mapcat neighbors world)) :when (live n (world cell))] cell)))

(defn life [initial-world] (iterate step initial-world))

Page 4: Cracking clojure

Primitives

4

Page 5: Cracking clojure

Collections

5

Page 6: Cracking clojure

Sequences

6

Page 7: Cracking clojure

Sequences

6

Page 8: Cracking clojure

Functions

7

Page 9: Cracking clojure

Functions

7

Page 10: Cracking clojure

Functions

7

Page 11: Cracking clojure

Compiler

8

Page 12: Cracking clojure

Casting spells

9

Page 13: Cracking clojure

Creating functions

10

Page 14: Cracking clojure

Creating functions

10

Page 15: Cracking clojure

Creating functions

10

Page 16: Cracking clojure

Creating functions

10

Page 17: Cracking clojure

Creating functions

10

Page 18: Cracking clojure

An example...

11

Page 19: Cracking clojure

map

12

Page 20: Cracking clojure

Sequence of lines

13

Page 21: Cracking clojure

Sequence of files

14

Page 22: Cracking clojure

Sequence of files

14

Page 23: Cracking clojure

Sequence functions

15

Page 24: Cracking clojure

You

16

Page 25: Cracking clojure

Lazy sequences

17

Page 26: Cracking clojure

18

Page 27: Cracking clojure

18

Page 28: Cracking clojure

Power

19

Page 29: Cracking clojure

Objects

20

Page 30: Cracking clojure

Maps as cheap objects

21

Page 31: Cracking clojure

Records

22

Page 32: Cracking clojure

Java

23

package domain;

public class Beer { private String beer; private String brewery; private float alcohol; private int ibu; public Beer(String beer, String brewery, float alcohol, int ibu) { super(); this.beer = beer; this.brewery = brewery; this.alcohol = alcohol; this.ibu = ibu; }

public String getBeer() { return beer; } public String getBrewery() { return brewery; } public float getAlcohol() { return alcohol; } public int getIbu() { return ibu; } public void setBeer(String beer) { this.beer = beer; } public void setBrewery(String brewery) { this.brewery = brewery; } public void setAlcohol(float alcohol) { this.alcohol = alcohol; } public void setIbu(int ibu) { this.ibu = ibu; }

@Override public int hashCode() { final int prime = 31;

int result = 1; result = prime * result + Float.floatToIntBits(alcohol); result = prime * result + ((beer == null) ? 0 : beer.hashCode()); result = prime * result + ((brewery == null) ? 0 : brewery.hashCode()); result = prime * result + ibu; return result; }

@Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Beer other = (Beer) obj; if (Float.floatToIntBits(alcohol) != Float .floatToIntBits(other.alcohol)) return false; if (beer == null) { if (other.beer != null) return false; } else if (!beer.equals(other.beer)) return false; if (brewery == null) { if (other.brewery != null) return false; } else if (!brewery.equals(other.brewery)) return false; if (ibu != other.ibu) return false; return true; }

@Override public String toString() { return "Beer [beer=" + beer + ", brewery=" + brewery + ", alcohol=" + alcohol + ", ibu=" + ibu + "]"; }}

Page 33: Cracking clojure

Java

23

package domain;

public class Beer { private String beer; private String brewery; private float alcohol; private int ibu; public Beer(String beer, String brewery, float alcohol, int ibu) { super(); this.beer = beer; this.brewery = brewery; this.alcohol = alcohol; this.ibu = ibu; }

public String getBeer() { return beer; } public String getBrewery() { return brewery; } public float getAlcohol() { return alcohol; } public int getIbu() { return ibu; } public void setBeer(String beer) { this.beer = beer; } public void setBrewery(String brewery) { this.brewery = brewery; } public void setAlcohol(float alcohol) { this.alcohol = alcohol; } public void setIbu(int ibu) { this.ibu = ibu; }

@Override public int hashCode() { final int prime = 31;

int result = 1; result = prime * result + Float.floatToIntBits(alcohol); result = prime * result + ((beer == null) ? 0 : beer.hashCode()); result = prime * result + ((brewery == null) ? 0 : brewery.hashCode()); result = prime * result + ibu; return result; }

@Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Beer other = (Beer) obj; if (Float.floatToIntBits(alcohol) != Float .floatToIntBits(other.alcohol)) return false; if (beer == null) { if (other.beer != null) return false; } else if (!beer.equals(other.beer)) return false; if (brewery == null) { if (other.brewery != null) return false; } else if (!brewery.equals(other.brewery)) return false; if (ibu != other.ibu) return false; return true; }

@Override public String toString() { return "Beer [beer=" + beer + ", brewery=" + brewery + ", alcohol=" + alcohol + ", ibu=" + ibu + "]"; }}

Fields and types

Construction

Getters

Setters

Hashing

Equality

Printing

Page 34: Cracking clojure

Data interfaces

24

Page 35: Cracking clojure

Data interfaces

24

Page 36: Cracking clojure

Data interfaces

25

Page 37: Cracking clojure

Data - Clojure vs Java

26

Page 38: Cracking clojure

Data - Clojure vs Java

26

Page 39: Cracking clojure

Polymorphism

27

Page 40: Cracking clojure

Generic access FTW

28

Page 41: Cracking clojure

Multimethods

29

Page 42: Cracking clojure

Multimethod dispatch

30

Page 43: Cracking clojure

Protocols

31

Page 44: Cracking clojure

State

32

Page 45: Cracking clojure

Atoms

33

Page 46: Cracking clojure

Refs

34

Page 47: Cracking clojure

Agents

35

Page 48: Cracking clojure

Destructuring

36

Page 49: Cracking clojure

for comprehensions

37

Page 50: Cracking clojure

for comprehensions

37

Page 51: Cracking clojure

Macros

38

Page 52: Cracking clojure

Macros

39

Page 53: Cracking clojure

Review

40

DATA CODE

HOSTCONCURRENCY

Page 54: Cracking clojure

Review

40

DATA CODE

HOSTCONCURRENCY

primitives

Page 55: Cracking clojure

Review

40

DATA CODE

HOSTCONCURRENCY

primitives

collections

Page 56: Cracking clojure

Review

40

DATA CODE

HOSTCONCURRENCY

sequences

primitives

collections

Page 57: Cracking clojure

Review

40

DATA CODE

HOSTCONCURRENCY

sequences

laziness

primitives

collections

Page 58: Cracking clojure

Review

40

DATA CODE

HOSTCONCURRENCY

sequences

laziness

FP

primitives

collections

Page 59: Cracking clojure

Review

40

DATA CODE

HOSTCONCURRENCY

sequences

lazinesssequence library

FP

primitives

collections

Page 60: Cracking clojure

Review

40

DATA CODE

HOSTCONCURRENCY

recordstypes

sequences

lazinesssequence library

FP

primitives

collections

Page 61: Cracking clojure

Review

40

DATA CODE

HOSTCONCURRENCY

recordstypes

sequences

lazinesssequence library

FP

primitives

collections

multimethodsprotocols

Page 62: Cracking clojure

Review

40

DATA CODE

HOSTCONCURRENCY

recordstypes

atoms

state

refs agents

sequences

lazinesssequence library

FP

primitives

collections

multimethodsprotocols

Page 63: Cracking clojure

Review

40

DATA CODE

HOSTCONCURRENCY

recordstypes

atoms

state

refs agents

sequences

lazinesssequence library

FP

primitives

collections

destructuring

multimethodsprotocols

Page 64: Cracking clojure

Review

40

DATA CODE

HOSTCONCURRENCY

recordstypes

atoms

state

refs agents

sequences

lazinesssequence library

FP

macros

primitives

collections

destructuring

multimethodsprotocols

Page 65: Cracking clojure

Review

40

DATA CODE

HOSTCONCURRENCY

metadata

recordstypes

atoms

state

refs agents

sequences

lazinesssequence library

FP

macros

primitives

collections

transientsdestructuring

multimethodsprotocols

Page 66: Cracking clojure

Review

40

DATA CODE

HOSTCONCURRENCY

metadata

recordstypes

atoms

state

refs agents

sequences

lazinesssequence library

FP

macros

primitives

collections

transientsdestructuring

namespaces

multimethodsprotocols

Page 67: Cracking clojure

Review

40

DATA CODE

HOSTCONCURRENCY

metadata

recordstypes

atoms

state

refs agents

sequences

lazinesssequence library

FP

macros

primitives

collections

transientsdestructuring

namespaces

recursion

multimethodsprotocols

Page 68: Cracking clojure

Review

40

DATA CODE

HOSTCONCURRENCY

metadata

recordstypes

atoms

state

refs agents

sequences

lazinesssequence library

FP

macros

primitives

collections

transientsdestructuring

namespaces

recursion

multimethodsprotocols

Java interop

Java libs

Page 69: Cracking clojure

Review

40

DATA CODE

HOSTCONCURRENCY

metadata

recordstypes

atoms

state

refs agents

sequences

laziness

futures promises

pmap

sequence library

FP

macros

primitives

collections

transientsdestructuring

namespaces

recursion

multimethodsprotocols

Java interop

Java libs

Page 70: Cracking clojure

Conway's Life

41

Implementation courtesy of Christophe Grandhttp://clj-me.cgrand.net/2011/08/19/conways-game-of-life/

"Blinker" configuration

Life's rules: If alive and 2 or 3 neighbors Then stay alive Else die If dead and 3 neighbors Then come to life

Page 71: Cracking clojure
Page 72: Cracking clojure
Page 73: Cracking clojure

Thanks!

• Twitter: @puredanger• Blog: http://tech.puredanger.com• Work: http://revelytix.com• My conferences

– Strange Loop - http://thestrangeloop.com– Clojure/West - http://clojurewest.com

If you want to pair on Clojure during Devoxx, ping me on Twitter!

43