Slide 1

Slide 1 text

0 to 35 mph with Clojure

Slide 2

Slide 2 text

Outline ● Clojure’s Guiding Principles ○ Simplicity ● What is Clojure? ● Clojure syntax ● Clojure examples ● Code is data

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

Hello, World!

Slide 5

Slide 5 text

Most languages Clojure It Looks Different ● When people come to Clojure the first they do is cringe ○ We all need just a little understanding and empathy ○ Yes, it looks different than languages you are accustomed to working in

Slide 6

Slide 6 text

Infix It Looks Different Prefix ● Infix Notation ○ Most languages use arithmetical operations ○ Where it is operators between operands ● Prefix Notation ○ Prefix notation is operators followed by operands

Slide 7

Slide 7 text

It Looks Different Infix Prefix (f arg1 arg2 arg3) ● Infix ○ Operand operator operand operator ● Prefix ○ Operator operand operand

Slide 8

Slide 8 text

● As software developers, we want to be able to build complex things ● Requirements of our software are becoming increasingly demanding and complicated ● This castle is complicated and intricate ○ We, as software developers, want to build complex structures like these ○ It has turrets, windows, roofs, internal rooms, a dungeon (which you can’t see) ○ It even has a witch ● If you look closely, you’ll see that this castle is knitted together ● What happens if ○ We want to replace the window ○ Replace the roof ○ Add another wing ● This becomes difficult with this approach. ○ It is a complex weaved pattern ○ It’s intertwined ○ Adding a new wing necessitates tearing a hole in the side of castle and mending it in ■ This would be difficult

Slide 9

Slide 9 text

○ It is resistant to change and isn’t’ flexible

Slide 10

Slide 10 text

● Unlike the knitted castle, this castle is made of logos ● Legos are small composable pieces ● Pieces that are not intertwined and bound the neighboring pieces ● We can snap them together into an infinite number of shapes ● If we need to ○ Replace the roof ○ The window ○ Add a wing ● If we need to pivot quickly, we could then make a resort instead ○ It already has a pool ● We can do this more easily do this with legos than the knitted castle ● I would say that the lego pieces are simple in their nature ○ They do one thing well, they snap/connect to another piece and you can easily disconnect them

Slide 11

Slide 11 text

Simple Made Easy ● Simple is not Easy ● Just because it’s easy doesn’t mean it’s simple ● Simplicity ○ Prerequisite for reliability ○ Ease of understanding ○ Ease of change ○ Ease of debugging ● Rich Hickey, the creator of Clojure gave a talk “Simple Made Easy” ○ He spoke about how software should be simple, but not necessarily easy ● Simple Made Easy ○ Simple is often erroneously mistaken for easy. i. "Easy" means "to be at hand", "to be approachable" ○ “Complex” means "being intertwined", "being tied together" ○ "Simple" is the opposite of "complex" ○ Simple != easy. ○ Often times simple is hard ○ Easy is overrated in the software industry. i. "Can I get this thing running in 5 seconds?" ii. Npm install everything iii. It does not matter if the result is a large ball of mud. iv. All it matters is to be done quickly.

Slide 12

Slide 12 text

● Simplicity matters in software ○ We should ask ourselves these questions: i. Does the software do what is supposed to do? ii. Is it of high quality? iii. Can we rely on it? iv. Can problems be fixed along the way? v. Can requirements change over time? ○ Complexity in software can be i. Interleaving, Entwining, Braiding responsibilities ○ Can I figure out what the system is doing and make changes? i. If it is a large system made of a million simple composable parts 1. “yes” it is more approached, maybe not simple, 2. You can make changes to the system 3. Add functionality ii. If is a large system made of complex things, then “no” it is more difficult to understand 1. Takes longer to comprehend systems 2. Takes longer to make changes to the system ● This is all true about Software Development. ● Rich Hickey applied these concepts to Clojure when he was developing it ● He really intended Clojure to be “Simple made easy”

Slide 13

Slide 13 text

What is Clojure? ● Lisp ● Dynamic Language ● Functional ● Concurrent Programming ● Polymorphic ● Hosted on the JVM

Slide 14

Slide 14 text

What is Clojure? ● Lisp ● Dynamic Language ● Functional ● Concurrent Programming ● Polymorphic ● Hosted on the JVM

Slide 15

Slide 15 text

Lisp ● Oldest high-level programming (after Fortran) ● Roots in Artificial Intelligence ● Code as data ○ Homoiconic ○ Rich macro system ● Other Lisps ○ Common Lisp, Racket, Scheme ● Parentheses ● Oldest high-level programming (after Fortran) ○ Strong abstractions that remove details about the computer ■ Such as memory management ■ Python, Ruby, PHP vs C, Assembly ● Roots in Artificial Intelligence ● Code as data ○ Homoiconic ■ Express programs in a programming language’s primitive data types ● When the reader (parser) reads a source file, the ABS built looks exactly like the source ● When you can access a piece of code as data, you can analyze and modify it just like any other data ● Your programming language doesn’t need to know this data represents code. ■ In most languages the AST’s data structure is inaccessible within the programming language ● The programming language space and the compiler space are forever separated ○ We’ll cover this later in more detail

Slide 16

Slide 16 text

What is Clojure? ● Lisp ● Dynamic Language ● Functional ● Concurrent Programming ● Polymorphic ● Hosted on the JVM

Slide 17

Slide 17 text

Dynamic Language ● Static vs Dynamic ● Manipulate program at runtime ○ Adding new code ○ Extending objects and definitions ○ Modifying the type system ● Many of these were first implemented Lisp ● Static vs Dynamic ○ The debate between static and dynamic language is not black and white ○ Haskell vs Clojure ■ Haskell ● Powerful type system that is checked at compile time ● If your program compiles it is free from common and not so common errors. ○ Prevents you from making silly mistakes ○ But also may prevent you from doing some things that may be viewed as valid ■ Clojure ● Short compilation step (basically just reading syntax) ● Practically no limits as to what can be done at runtime ● Won't prevent me from silly mistakes. ● Manipulate program at runtime ○ Metaprogramming ○ Macros ○ Closures

Slide 18

Slide 18 text

○ Ruby, Python, Lisps ● Many of these were first implemented in Lisp

Slide 19

Slide 19 text

What is Clojure? ● Lisp ● Dynamic Language ● Functional ● Concurrent Programming ● Polymorphic ● Hosted on the JVM

Slide 20

Slide 20 text

Functional ● Mostly functional ○ Philosophy that functional programs are more robust ● Functions are first class citizens ● Immutable ○ State is a main source of complexity, and hence bugs ○ Can it be done in languages that support mutability? ○ Implications for concurrent programming ● Mostly functional ○ Provides the tools to avoid mutable state ○ Clojure is impure ■ Doesn’t force your program to be referentially transparent ● Given a function and an input value, you will always receive the same output

Slide 21

Slide 21 text

Functional ● Mostly functional ○ Philosophy that functional programs are more robust ● Functions are first class citizens ● Immutable ○ State is a main source of complexity, and hence bugs ○ Can it be done in languages that support mutability? ○ Implications for concurrent programming ● Functions are first class citizens ○ You can pass functions as arguments ○ Ruby, Python, Javascript support this ●

Slide 22

Slide 22 text

Functions are First Class Citizens 1) Function name “signature” that takes a function named “signoff” as an argument 2) Pass function as argument to “signature” ● Functions are first class citizens ○ You can pass functions as arguments ○ Ruby, Python, Javascript support this

Slide 23

Slide 23 text

Functional ● Mostly functional ○ Philosophy that functional programs are more robust ● Functions are first class citizens ● Immutable ○ State is a main source of complexity, and hence bugs ○ Can it be done in languages that support mutability? ○ Implications for concurrent programming ● Immutable ○ After switching to an immutable language, I have found that state is the main source of complexity, and hence bugs ○ Difficult concept to convey to folks who work in languages that support mutablity ○ I can say that overtime I have experienced fewer bugs. ○ It’s as if an entire class of bugs ceased to exist ○ Can it be done in languages that support mutability? ■ Yes, but with great effort ■ The easiest way to avoid mutating state is to use immutable data structures. ■ Clojure provides a set of immutable data structures ● lists vectors, sets and maps. ■ Since they can’t be changed, 'adding' or 'removing' something from an immutable collection ● It means creating a new collection just like the old one but with the needed change ● New versions can share structure with the prior version to maintain performance ○ I.e. it is not a naive copy ■ I find that is one of the difficulties/impedances for folks

Slide 24

Slide 24 text

■ coming from mutable languages ● Ironically, this is what makes the functional programs easier to reason about

Slide 25

Slide 25 text

Immutable 1) Assign “name” to “Travis” 2) Reassign “name” to “Jonathan” ● Mostly functional ○ Provides the tools to avoid mutable state ○ Functions as first-class objects ○ Emphasizes recursive iteration instead of side-effect based looping ○ Clojure is impure ■ Doesn’t force your program to be referentially transparent ● Given a function and an input value, you will always receive the same output ● Functions are first class citizens ○ You can pass functions as arguments ○ Ruby, Python, Javascript support this ● Immutable ○ After switching to an immutable language, I have found that state is the main source of complexity, and hence bugs ○ I find that this is a difficult concept to convey to folks who work in languages that support mutablity ○ I can say that overtime I have experienced fewer bugs. ○ It’s as if an entire class of bugs ceased to exist ○ Can it be done in languages that support mutability? ■ Yes, but with great effort ■ The easiest way to avoid mutating state is to use immutable data structures.

Slide 26

Slide 26 text

■ Clojure provides a set of immutable data structures ● lists vectors, sets and maps. ■ Since they can’t be changed, 'adding' or 'removing' something from an immutable collection ● It means creating a new collection just like the old one but with the needed change ● New versions can share structure with the prior version to maintain performance ○ I.e. it is not a naive copy ■ I find that is one of the difficulties/impledences for folks coming from mutable languages ● Ironically, this is what makes the functional programs easier to reason about

Slide 27

Slide 27 text

Immutable 1) Assign “name” to “Travis” 2) Reassign “name” to “Jonathan”

Slide 28

Slide 28 text

What is Clojure? ● Lisp ● Dynamic Language ● Functional ● Concurrent Programming ● Polymorphic ● Hosted on the JVM

Slide 29

Slide 29 text

What is Clojure? ● Lisp ● Dynamic Language ● Functional ● Concurrent Programming ● Polymorphic ● Hosted on the JVM ●

Slide 30

Slide 30 text

Concurrent Programming ● Multi-threaded ● Immutable data structures can be shared across threads ● Allows state change ○ Software Transactional Memory System ○ Ensure consistency and reliability ○ No need to manage locks, and etc. ● Today’s applications are being asked to do more and more ○ Manage more data and faster ● Multi-threaded ● Immutable data structures can be shared across threads ○ All of clojure core data structures are immutable ○ This is a benefit of functional programming and immutability ● Allows state change ○ Multi-threaded applications can help address these requests ■ Core data structures are immutable and can be shared readily between threads ■ Provides mechanism to ensure that when state changes it remains consistent and reliable ■ This is done with STM

Slide 31

Slide 31 text

What is Clojure? ● Lisp ● Dynamic Language ● Functional ● Concurrent Programming ● Polymorphic ● Hosted on the JVM ●

Slide 32

Slide 32 text

What is Clojure? ● Lisp ● Dynamic Language ● Functional ● Concurrent Programming ● Polymorphic ● Hosted on the JVM ●

Slide 33

Slide 33 text

Polymorphism ● Make programs easier to change and extend ● Presenting the same interface for differing data types. ● This achieved in languages like Ruby with “Duck Typing”

Slide 34

Slide 34 text

What is Clojure? ● Lisp ● Dynamic Language ● Functional ● Concurrent Programming ● Polymorphic ● Hosted on the JVM ●

Slide 35

Slide 35 text

What is Clojure? ● Lisp ● Dynamic Language ● Functional ● Concurrent Programming ● Polymorphic ● Hosted on the JVM ●

Slide 36

Slide 36 text

Hosted on the JVM ● A hosted language ● Compiles all functions to JVM bytecode ● Access to Java’s rich ecosystem ○ Java Interop

Slide 37

Slide 37 text

What is Clojure? ● Lisp ● Dynamic Language ● Functional ● Concurrent Programming ● Polymorphic ● Hosted on the JVM ●

Slide 38

Slide 38 text

Benefits I’ve Experienced ● About productive as I was with Ruby ○ Ruby - 3’ish years ○ Clojure - 1 year ● Focus on domain problem rather than language ● Productivity gains on server (relative to Ruby) ● Huge productivity gains on client (relative to JavaScript) ● Attribute to ○ Being a more experienced developer ○ Less magic in Clojure (than Ruby) ■ What’s happening in an application is more transparent ○ Minimal syntax ■ Apart from parenthesis ■ Managed by ide/text-editor ○ Immutability ■ Again, I found that a lot of complexity derives from maintaining state ■ The less amount of state you manage, the less complexity ■ This is provided to you b/c data structures are immutable ● It makes it difficult to maintain state ● State that is maintained ○ Has a very explicit scope and small surface area ○ Or is pushed outside the application all together ■ The db ○ Language simplicity/terseness ■ Less noise ■ No class constructors

Slide 39

Slide 39 text

■ Semi-colons ■ Etc ○ Most domain concepts/objects are just maps ■ not represented as classes all with their special methods ■ This is equivalent to all class responding to the same methods ○ REPL

Slide 40

Slide 40 text

ClojureScript is a THING! ● Yes, you can write ClojureScript ● It compiles to JavaScript ● Implements the same’ish interface as Clojure ○ So you get a lot of the same benefits ○ Apart from macros and concurrency ● No more strange JS syntax. ● ClojureScript is predictable and very nice to work with ● The JavaScript community is moving towards functional programming ○ Immutable.js ○ Ramda ○ Lodash ● I say that the JavaScript community is being pushed by the functional programming ● There are so many aspects that ClojureScript simplifies ○ No npm, yarn, and whatever next month is ○ No special libraries for immutable data structures ○ No special libraries for functional programming functions ○ It’s is just given to you by ClojureScript

Slide 41

Slide 41 text

Let’s See Some Clojure! ●

Slide 42

Slide 42 text

Function Signature ( ) (fun arg1) (operator operand) (add-friend “Jonathan”) ●

Slide 43

Slide 43 text

Let’s See Some Clojure! ( ) (fun arg1) (operator operand) (add-friend “Jonathan”) ●

Slide 44

Slide 44 text

Let’s See Some Clojure! ( ) (fun arg1) (operator operand) (add-friend “Jonathan”) ●

Slide 45

Slide 45 text

Let’s See Some Clojure! ( ) (fun arg1) (operator operand) (add-friend “Jonathan”) ●

Slide 46

Slide 46 text

● This “def” is defined within a namespace ● We “def” “friends” to a vector containing the string “Jonathan”

Slide 47

Slide 47 text

● We “conj” (append to vector) the string “Ben”

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

● “Let” is a clojure special form ● Create a “let” binding ○ Binding the vector “friends” to [“No-one”] ○ “Ben” is then “conj”ed onto the vector “friends” ● The important thing to note is that “friends” in the “let” block is scoped to the “let” block ● Outside of the “let” block, “friends” is [“Jonathan”]

Slide 50

Slide 50 text

● “Let” is a clojure special form ● Create a “let” binding ○ Binding the vector “friends” to [“No-one”] ○ “Ben” is then “conj”ed onto the vector “friends” ●

Slide 51

Slide 51 text

● The important thing to note is that “friends” in the “let” block is scoped to the “let” block ● Outside of the “let” block, “friends” is [“Jonathan”]

Slide 52

Slide 52 text

● This “def” is defined within a namespace ● We “def” “friends” to a vector containing the string “Jonathan”

Slide 53

Slide 53 text

Slide 54

Slide 54 text

● We create a function named “add-friend” ● The function “add-friend” ○ Takes one argument (name “friend”) ○ We add the “friend” to the vector “friends”

Slide 55

Slide 55 text

No content

Slide 56

Slide 56 text

● If we evaluate friends again ○ The original “friends” def has not been modified ●

Slide 57

Slide 57 text

● Function “str/upper-case” that uppercases a world

Slide 58

Slide 58 text

● A function called “shout-at-friends” that takes a collection of friends ● Uses the function “map” to iterate over each item in the collection and applies the function “str/upper-case” to each element

Slide 59

Slide 59 text

● We provide the function “add-friend” to “shout-at-friends” ● “add-friend” is evaluated before “shout-at-friends” is evaluated. ● “Add-friend” returns a collection “[“jonathan”, “ben”]”

Slide 60

Slide 60 text

● Really we want to yell at our friends ● We define a function “yell” that takes a collection of friends ● It “map”s over each item in the collection and applies an anonymous function to each element in the collection ○ The anonymous function takes one argument and adds “!” to each argument

Slide 61

Slide 61 text

● Now we are yelling at our friends! ● Exactly what we want ● But it is a bit messy ○ We get this deeply nested function which can be difficult to reason about

Slide 62

Slide 62 text

● This is a much nicer way to accomplish yelling at our friends ● The “->” is a macro ● It is the “thread-first” macro ● The first argument is a collection ○ The return value of each function is provided at the first argument to the next function

Slide 63

Slide 63 text

● What code is being evaluated? ● We can use a special form that Clojure provides called a “macroexpand” ○ “Macroexpand” returns a “macro”s expansion ○ Meaning it returns the data structure that will be evaluated ● The return value looks exactly like the deeply nested function we wrote previously ○ Except that each function is prefixed with the namespace ○ In this case, the namespace is “user”, the default clojure namespace ● The macro was able to manipulate the program at runtime

Slide 64

Slide 64 text

Code as Data ● Clojure is homoiconic ○ Express programs in a programming language’s primitive data types ○ Your code is data and data is code ● Code as data ○ Homoiconic ■ Express programs in a programming language’s primitive data types ● When the reader (parser) reads a source file, the ABS built looks exactly like the source ● When you can access a piece of code as data, you can analyze and modify it just like any other data ● Your programming language doesn’t need to know this data represents code. ■ In most languages the AST’s data structure is inaccessible within the programming language ● The programming language space and the compiler space are forever separated

Slide 65

Slide 65 text

Reader “(+ 1 2 3)” (+ 1 2 3) Abstract Syntax Tree Evaluator 6

Slide 66

Slide 66 text

Reader “(+ 1 2 3)” (+ 1 2 3) Abstract Syntax Tree Evaluator 6 Accessible To You! This is where Macros live

Slide 67

Slide 67 text

● Our trusty old example of addition

Slide 68

Slide 68 text

● The “read-string”, the “Reader portion” from the previous slide is available to use a function ● The string “(+ 1 2 3)” is passed to the “read-string” function ● It returns an unevaluated clojure list ○ Which is data that represents our code!

Slide 69

Slide 69 text

● The “eval” function is the “Evaluator” from the previous slide ● It takes the clojure list (that represents our code) and evaluates the expression and returns 6! ● Macros live between the reader and evaluator steps

Slide 70

Slide 70 text

● This is an “if” expression ● If predicate returns true (which “true” does) ○ Then “My best friend!” is returned ○ Otherwise “I’ve lost you forever :/” ● In this case, “My best friend!” is returned

Slide 71

Slide 71 text

● There is also the “when” macro ● It returns ○ the value supplied when the predicate evaluates to “true” ○ Otherwise it returns “nil” ● In this case “when” returns “My best friend!”

Slide 72

Slide 72 text

● In this case “when” returns “nil” because “false” does not evaluate to “true” ● “When” is a macro ● Remember “macro”s live between the “reader” and “evaluator” and is accessible to clojure ○ Clojure can manipulate the data structures returned from the “reader” before it is sent to the “evaluator”

Slide 73

Slide 73 text

● We can use a special form that Clojure provides called a “macroexpand” ○ “Macroexpand” returns a “macro”s expansion ○ Meaning it returns the data structure that will be evaluated ● In this case, we see that “when” is just syntactic sugar for an “if” expression

Slide 74

Slide 74 text

Code is Data

Slide 75

Slide 75 text

Outline ● Clojure’s Guiding Principles ○ Simplicity ● What is Clojure? ● Clojure syntax ● Clojure examples ● Code is data

Slide 76

Slide 76 text

References ● https://clojure.org/ ● http://www.braveclojure.com/ ● http://blog.venanti.us/why-clojure/ ● https://en.wikipedia.org/wiki/Lisp_(programming_language) ● https://en.wikipedia.org/wiki/Abstract_syntax_tree ● http://blog.muhuk.com/2014/09/28/is_clojure_homoiconic.html#.WL7HsxLyvU I ● http://stackoverflow.com/a/4938609/222185 ● https://en.wikipedia.org/wiki/Dynamic_programming_language ● https://robots.thoughtbot.com/back-to-basics-polymorphism-and-ruby