I came across Clojure when I was trying to figure out what language and ecosystem I wanted to spend the next ten years developing in.

The functional programming paradigm is not going away. The dawn of functional reactive programming in Javascript ushered in a new wave of functional programmers, with developers routinely using higher order functions in libraries such as RxJs and Redux. Angular and React are built upon functional concepts.

Javascript is indeed a powerful language, but with the constant churn of frameworks and libraries that require a significant investment of time to master, perhaps there is a better alternative language for doing functional front-end development in 2019?

I came across new languages like Elm, that promised practically zero run-time errors and crashes in production code due to the advanced type system. The Elm programmers all seem quite happy too, but there just aren’t too many jobs out there. I looked at Haskell as well, as it seemed like a great way to master functional programming theory but offered little in the way of web development and limited use commercially.

Then I came across Clojure and ClojureScript. It is easy to dismiss Clojure at first, as there aren’t a huge amount of companies using it. However, there are a huge amount of companies with existing code and libraries written in Javascript and Java. Clojure interops with both of these languages nicely, so perhaps we might see more Clojure jobs advertised in the future.

If you come from the JavaScript realm, imagine js but with RxJs, Immutable and Lodash built into the language. Shivek Khurana

The following chart from the StackOverflow developer survey 2019 is also interesting:

The chart is interesting for a few reasons:

Developers with over 10 years of experience are working with functional languages such as Erlang, F# and Clojure. Is this significant?

Clojure had the highest median salary of all the languages

Not bad for a non-mainstream language. Clojure developers also seem happier:

The more I looked into Clojure, the more fascinated I became with its opinionated creator, Rich Hickey.

You don’t level up by switching games all the time, but by sticking with one long enough to gain advanced skills. And, you need to be careful to recognize the actual game involved. Programming mastery has little to do with languages, paradigms, platforms, building blocks, open source, conferences etc. — Rich Hickey

Clojure is weird. I have developed software in over 12 languages and been programming for well over a decade, but I have never actually come across a Lisp dialect before.

© Randall Munroe https://xkcd.com/

Lisp was originally specified in 1958 and was heavily influenced by Alonzo Church’s lambda calculus. In language terms it is pretty ancient, so why did Rich Hickey use a Lisp variation when designing Clojure, a language designed in 2007?

Well it turns out that Lisp as a language is incredibly powerful and expressive, with a simple syntax.

“Lisp is a programmable programming language.” — John Fodararo

Lisp gives developers the power to extend the Lisp language in many different ways, which ultimately means that you end up writing less boilerplate code and the code will ultimately resemble the thoughts and intentions of the programmer more closely.

Find out more about why Lisp is a great basis for programming languages here. Now back to Clojure…

Clojure provides an environment and language that has been designed to encourage functional programming, but it also has features to prevent a lot of bad practices and bugs.

Interoperability — Clojure runs on the Java virtual machine, which gives it the ability to seamlessly access existing Java libraries. This makes it perfect for integrating with existing Java libraries and code. ClojureScript also provides excellent interoperability with Javascript. as it uses the Google Clojure compilter to compile ClojureScript down to JS code. This allows you to use Javascript libraries in ClojureScript with very little overhead.

— Clojure runs on the Java virtual machine, which gives it the ability to seamlessly access existing Java libraries. This makes it perfect for integrating with existing Java libraries and code. ClojureScript also provides excellent interoperability with Javascript. as it uses the Google Clojure compilter to compile ClojureScript down to JS code. This allows you to use Javascript libraries in ClojureScript with very little overhead. Immutable data structures — Most Clojure data structures are immutable by default. Clojures lists, vectors, sets and maps cannot be modified. Instead, new data structures must be created to change them. Under the hood, Clojure uses Red-black tree algorithms to do this in a clever way to avoid having to copy the whole data-structure each time, so it is blazingly fast too.

— Most Clojure data structures are immutable by default. Clojures lists, vectors, sets and maps cannot be modified. Instead, new data structures must be created to change them. Under the hood, Clojure uses Red-black tree algorithms to do this in a clever way to avoid having to copy the whole data-structure each time, so it is blazingly fast too. Functional Programming — First class functions and support for tail recursion, i.e. you can recursively call a function without running out of stack memory

First class functions and support for tail recursion, i.e. you can recursively call a function without running out of stack memory Extensible Abstractions — Clojure allows you to write functions that work at a higher level of abstraction than other languages. For example, all of the Clojure data-structures provide a seq interface, which means you can write a single function to handle any form of data-structure.

— Clojure allows you to write functions that work at a higher level of abstraction than other languages. For example, all of the Clojure data-structures provide a seq interface, which means you can write a single function to handle any form of data-structure. Code as Data — The Lisp foundation allows developers to write code as data. This means that the language and any code that you write can be modified automatically at run-time using the macro system. With Clojure, you can choose to extend the compiler with user defined code.

— The Lisp foundation allows developers to write code as data. This means that the language and any code that you write can be modified automatically at run-time using the macro system. With Clojure, you can choose to extend the compiler with user defined code. Runtime Polymorphism — Clojure multimethods avoid many of the problems associated with Object Oriented programming, types and inheritance

— Clojure multimethods avoid many of the problems associated with Object Oriented programming, types and inheritance Concurrent & Parallel Programming- Clojure simplifies multi-threaded programming. The core data structures are immutable, so can be shared between threads and implements a software transaction memory (STM) system. Think of this as SQL like Transactions baked into a programming language. Clojure atoms can be shared between threads in a synchronous and independent manner.

Clojure simplifies multi-threaded programming. The core data structures are immutable, so can be shared between threads and implements a software transaction memory (STM) system. Think of this as SQL like Transactions baked into a programming language. Clojure atoms can be shared between threads in a synchronous and independent manner. Productivity — Clojure is built on little functions that do useful things. It might seem like a lot of effort to learn at first, but every function you learn is a function that you don’t need to write yourself. The pay-off for this cumulative knowledge is an increase in developer productivity, the cost is that there is more stuff to learn.

— Clojure is built on little functions that do useful things. It might seem like a lot of effort to learn at first, but every function you learn is a function that you don’t need to write yourself. The pay-off for this cumulative knowledge is an increase in developer productivity, the cost is that there is more stuff to learn. Testing — Clojure.spec is awesome and it is far easier to test functions than mocking complex objects and relations in OOP

— Clojure.spec is awesome and it is far easier to test functions than mocking complex objects and relations in OOP Dynamic Development— The Read Eval Print Loop (REPL) allows you to run code interactively, you can write code interactively without having to keep compiling and starting from the beginning each time. Take a look at the Flappy Bird video below, I have never seen another language do this and it blew my mind watching this demo:

The Clojure Language

I thought it might be helpful to take a look at the language in a bit more detail. Clojure is interesting because the language syntax itself is simple compared to Javascript, but there are a lot of new concepts, functions and features available to the developer.

So before we get started, make sure you understand that:

The structure and syntax of ClojureScript is easy to pick up

There are a few basic types (nil, Numbers, Strings, Characters, Keywords, Symbols)

There are a few basic data structures and collections (Lists, Vectors, Maps, StructMaps, ArrayMaps & Sets)

There are a ton of operations that can be used to manipulate these data structures in different ways

There are exotic Clojure concepts like Macros, Sequences, Transients, Multimethods, Protocols, Atoms, Reducers, Software Transactional Memory etc that extend the language and provide a lot of power, but can take some time to understand

Most of these advanced features are simple function calls, so learning ClojureScript is really a case of learning what each little function does and is called. The more you work with Clojure, the more experience you will get with these functions.

Although it might seem like a lot to learn, remember that ultimately these little functions each do something useful that the developer would otherwise have to write manually.

The fact that a lot of Clojure programmers are not beginners as well doesn’t help, as the documentation can make it hard to understand what the function or language feature does.

If you want to learn ClojureScript then I highly recommend that you study the ClojureScript Cheatsheet to begin with, which gives you a map of the common language features you may need.

“Simplicity is hard work. But, there’s a huge payoff. The person who has a genuinely simpler system — a system made out of genuinely simple parts, is going to be able to affect the greatest change with the least work. He’s going to kick your ass. He’s gonna spend more time simplifying things up front and in the long haul he’s gonna wipe the plate with you because he’ll have that ability to change things when you’re struggling to push elephants around.” Rich Hickey

Take a look at some of the functionality of the Clojure language below for inspiration. You can find similar examples in the official clojure docs, which should help you get an idea of how each bit of the language works. Alternatively you can follow some of my other articles, such as Building a REST API in Clojure.

Comments

In Clojure, comments are denoted by a ; e.g. ;this is a comment

Clojure is weird because it doesn’t use , like other languages, in fact it treats all commas as white-space!

{:a 1 :b 2} ;is equivalent to

{:a 1, :b 2} ;because the compiler treats the comma as white-space

Functions & Variables

Functions can be defined using the def function as follows:

(def hello-world

(fn [name]

(str "Hello, " name))) (hello-world "Chris")

One of the key concepts in Clojure is that the first parameter in a parenthesis is typically the function you want to call. So to apply the add operator to two number we might call (+ 1 2)

Another thing to note is that the function arguments in this case are the numbers 1 and 2. In Clojure comments are treated as whitespace and spaces separate function arguments.

Clojure also lets you define anonymous functions using the # and % characters and def.

(def hello-world

#(str "Hello, " %)) (def display-car

#(str "My car is a " %1" " %2)) (display-car "Nissan" "Micra")

You can also use def to define variables:

(def myname “FunctionalHuman”)

(println myname)

Clojure also has a defn function, which allows you to easily define a named function and provide metadata. This provides a bit more flexibility and allows you to add some extra information to the function call.

(defn hello-world [name]

(str "Hello, " name)) (hello-world "Functional Human")

Notice how we were able to drop the fn and go straight to the argument parameter?

Documentation baked in…

Wouldn’t it be cool if a language had documentation built right into the language itself?

(def my-age "This is my age variable" 33)

We can also define a function with metadata:

(defn display-car "Display a car make and model" [make model]

(str "My car is a " make " " model))

We can then display the documentation for this function using:

(use 'clojure.repl) ; Import the doc function for repl

(doc display-car)

We can also search for any car related function in our code using:

(find-doc "car")

Binding functions with def and Destructuring

let is a special form that allows us to create lexical bindings of data structures to symbols within the lexical context of let. To put this in plain English and Javascript terms, this means you can define a symbol that is locally scoped within the let function.

(def my-line [[10 15] [20 25]])

(let [[p1 p2] my-line

[x1 y1] p1

[x2 y2] p2]

(println "Line from (" x1 "," y1 ") to (" x2 ", " y2 ")")) ;= "Line from ( 10, 15 ) to ( 20, 25 )"

So the let in the above code is basically saying, define variables p1 and p2, x1, y1, x2, y2 in the scope of let. These values are not accessible outside of the let expression so they are locally scoped. This example also uses destructuring, something that isn’t intuitive at first but is super cool.

The first bit of destructuring is the [[p1 p2] my-line This takes the input value in my-line, which it expects to be a vector of coordinate pairs, and assigns each pair to the p1 and p2 vectors. p1 then becomes [10,15] and p2 becomes [20,25]. Then we can use some more destructuring to tease apart the individual coordinates, so x1 becomes 10 and y1 becomes 15 etc.

This is equivalent to the Javascript ES6 destructuring argument:

//Javascript ES6 destructuring

let [[x1,y1],[x2,y2]] = [[10,15],[20,25]];

Clojure has two types of destructuring. We have seen sequential Destructuring already in our let statement above.

Here is another example of sequential destructuring:

(def my-list [1 2 3])

(let [[x y z] my-list]

(println x y z)) ;= 1 2 3

Clojure can also do associative destructuring. Let’s look at an example where we define a map of values relating to a client. A map in Clojurescript is a bit like defining an object with key value pairs in Javascript;

// In Javascript we might use an object to store key value pairs

let client = {

name: "Super Co.",

location: "Philadelphia",

description: "The worldwide leader in plastic tableware"

}; console.log(client["name"]);

In Clojurescript the syntax is similar, although we are using curly brackets {} to denote the map and all keys are prefixed with a colon :key

(def client {:name "Super Co."

:location "Philadelphia"

:description "The worldwide leader in plastic tableware."})

This lets us access properties with the (:key map)

(println "Client name is " (:name client))

Here we can use associative destructuring to map the properties of client to our local variables defined in let:

(let [{myname :name

mylocation :location

mydescription :description} client]

(println myname mylocation "-" mydescription)) ;= Super Co. Philadelphia - The worldwide leader in plastic tableware.

Notice that we again enclose the destructuring arguments in square brackets? Inside the destructuring we have a map, enclosed by the curly brackets and then we pass in the client so that we end up mapping the values in the client to our local variables (prefixed with my).

Associative destructuring is neat because if a :key doesn’t exist then the value will default to nil, and we can also supply a default value.

(let [{category :category, :or {category "Category not found"}} client]

(println category))

Notice how we have the format [{map :or { defaultmap}} client]?