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
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
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
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.
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”
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
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
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
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 •
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
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
“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.
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
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
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
• 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
“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”]
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
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
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
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
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 • It takes the clojure list (that represents our code) and evaluates the expression and returns 6! • Macros live between the reader and evaluator steps
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”
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