Why Clojure?

Why Clojure?

I could send you all to read the Clojure rationale and a summary of its features. But instead, I will write about it here. In fact, you are still encouraged to go and read these links since there is a value in reading them first hand from Rich. This post is full of pointers to hours of reading material which might be hard to swallow all at once. I still recommend reading it though.
My take on why learning and using Clojure in production is a bit different than the official links above. I touch the main points here.

Concurrency and the multi-core reality

Our processors are multi-core (want to know why?) and the reality is concurrent. What do I mean by that? Well, unless you are writing code which is purely algorithmic, most programs were written to interact with the real world. If not directly, then to serve other programs that do so. Some programs are just big functions (like compilers) but most of them are not.
And what do know? You would expect more than a single person to use your program at the same time. If your program does not interact with human actions directly (like a user interface for example) the events that are generated from this usage come in an unexpected time or order and can take an unknown amount of time to process. Be those events network packets, HTTP requests, RPC calls, hardware interrupts, you name it. It is not surprising that the operating systems are, in nature, asynchronous and concurrent. The real world is.

Now let’s talk about data. I hope I have already convinced you by now that most practical programs tend to be concurrent and run on a multi-core CPU and on an OS with asynchronous APIs.
Another simple truth about programs is that what they do most of the time is transforming data. And you already know what mama said about changing data concurrently. True. It is hard to do right. Clojure keeps this in mind.

  • All data structures are immutable and persistent by default. Worry not! Each piece of data in hand is your own private copy that nobody can change. Share data freely.
  • Now, the problem of data sharing is simply defined by combining several transitions to the same data. This is handled gracefully by Clojure. More on that later.

Functional programming is a good thing

Functional programming is a good thing. Clojure combines a few key concepts to be worthy of the title “a functional programming language”:

  • First-class functions: This means that functions are the building blocks of your program. Not classes, not packages, not modules. It also means that functions can be easily created on the fly (a.k.a anonymous functions) and also be passed to other functions as arguments and return from functions. The latter characteristic enables you to write higher-order functions, which are a powerful abstraction tool.
  • Immutable and persistent data structures by default. We have talked about it above. Note that this is only the default. Not the only option. This is a pragmatic approach to handling data.
  • Dynamic. Wait. what? That’s surprising. Most of the functional languages are statically typed (Haskel, the ML family, F#). Clojure is not and that is pretty refreshing. It enables very rapid development (less safe though). Note, that since Clojure is a hosted language, mainly on the JVM, it is still strongly typed and still has a dynamic type safety provided by the JVM. It has its drawback in writing correct code in large projects, but we will talk later on how Clojure approaches this in a separate post.
  • Finally, functional programming makes you think differently about problem-solving than you are used to. This itself is worthwhile and I wrote about it here.

Polymorphism

Polymorphism is also a good thing. It is useful for generating a flexible and concise code that can be easily changed later. But Clojure does not rely only on the JVM polymorphism which is type-based. It enhances it greatly by using protocols (similar to Go) and with multi methods, which is completely dynamic (runtime), dispatch by everything you want way. This rich polymorphism feature set is very flexible and powerful abstraction tool.
A nice manifestation of this is how Clojure solves the expression problem. A classical software design problem.

State and identity

Immutable and persistent data structures are only half of the story. The other half is Clojure’s unique approach to data. This deserves another post by itself, but I will try to sell you this shortly. Clojure dissects the data definition to two. Identity, which is just the name, (not a name as in ‘Dad` which might be ambiguous, but more an entity with a state. An example of identity would be “Alferd’s supermarket” or “today”. Identity represents the world for the program.
The value associated with the identity defines all things one can observe in the supermarket at a specific point in time. A snapshot if you will. For example, the number of cucumbers on the shelf. The number of working cashiers. If the supermarket is open or not. ‘Tuesday’ (for today).
Now, we can talk about identity as a series of different (and immutable) states that undergo safe transformations over time. The state itself is not changed. The identity just transforms and gets a new state. Today has the state ‘Tuesday’ at some point in time.
This is a hair worth splitting. It enables the programmer to share an identity between different threads or actors and then redefines the problem of concurrent access as a problem of combining several such transformations in a safe way. This problem is then solved in the Clojure standard library in an elegant way by vars, agents, refs, and atoms.

Pragmatism

Clojure is a pragmatic language. And this is, for me, a really appealing argument. Clojure goes a long way to sell us several ideas that are far from modern traditional programming (Lisp, functional programming, laziness, homoiconicity, etc.) but on the other hand, it does not bend your arm. Do you want to use mutable data structures (maybe for speed)? Okay. Do you wish to turn off default laziness? Be my guest.
Clojure hosted on the JVM is also a part of this pragmatic approach. In today’s industry, there are many clients who would require you to deliver programs that practically can only be run on the JVM. This might be because of various hardware or security compliance.
In addition, the JVM already has several decades of work invested in it and many wheels that do not need reinvention. To count a few, a decent garbage collection, and operating systems portability.
Do you know that the phase of not-big-enough-ecosystem a new language has to pass before people start to embrace it? Well, Clojure just skipped it. Java interop is free and hence all of Java’s enormous ecosystem is at your fingertips. Either use it directly or wrap it in a thin Clojure layer to make your life more functional.

Development

The development of a Clojure project is fun. This is because of a secret weapon, inherited from the Lisp family called the REPL, an acronym for read-eval-print-loop. The repl is a Clojure process that runs side by side to your IDE. It has a simple prompt and in this prompt, you can run Clojure (or Java) code. It is simple to ask the repl to hot load the code you have just edited, evaluate it, and print the result. This makes your development feedback loop a lot tighter. The time it takes from when you have written some code or edited an existing code, to when you actually see if it works as expected is reduced to almost zero. Want to access the code docs- call the repl. Want to read the imported function source code? Ask the repl. Want to try some small code snippet to see if it does what you expect? Just type it at the repl and hit enter. Most IDE’s have the ability to hook into an existing repl and use it as a server to evaluate the code inside the IDE as you type it. This is a truly amazing development experience.

Ready to learn Clojure?

Sharing is caring!

Leave a Reply

Your email address will not be published. Required fields are marked *

4 × five =