Assimilating with Clojure

Assimilating with Clojure

Sarah Sunday

October 27, 2016

Functional Programming nowadays is seen as kind of sexy by some sects of programmers and developers. Object Oriented Programming has for so long been a crutch, and using functional programming languages seems liberating and more efficient. It feels like a new toy.

Which it really isn’t, but, programming styles, like fashion, come and go in cycles. What is cool one decade may be lame another, and then two decades later it becomes the big "thing." One such programming language riding with this wave of the return of functional programming is Clojure.

Clojure is basically a mish-mash of Common LISP and Java. It is "functional" so everyone thinks it is cool. But it has Java Interop so it feels comfortable; you can use the same tools that you have been using for so long without having to do a little dance. There is a proverbial safety net of support. It looks slick, doesn’t have some of the baggage of Java’s design, and still uses the JVM, which is basically what people care about.

Although I understood why people thought it was cool, I was initially skeptical of Clojure. Because, unlike the people fascinated by it, I didn’t have the honor (pain) of experiencing OOP/Java systems for many years before engaging with Clojure. My first language was Python and the second was Common LISP, which I learned concurrently with Java.

As a result of this (perhaps odd) learning path, I became a LISP fan. My perspective of programming was irrevocably altered. Tainted, maybe, depending on your point of view.

I find this image to be particularly instructive and generally accurate of my programming attitude following my experience with Common LISP:

posts/2016-10-14-assimilating-with-clojure/lisp-views.png
Photo courtesy @robotickilldozr

This image may offend some programmers—including Common LISPers who believe Common LISP should be represented by Captain Picard, the popular and intellectual Starship Captain of "Star Trek: The Next Generation" series, instead of the pictured Captain Kirk. But I still prefer Common LISP as the hot-headed and tactical Captain Kirk of "Star Trek: The Original Series" because I’m a fan of the character.

Regardless of Star Trek captain preferences, the chart gets the job done. It conveys that LISPers have a different view on other languages and on programming in general.

And with this skewed perspective, I continued on with my life.

Eventually Clojure and I met. I began to learn and engage with it cautiously. The learning curve was like meeting an old friend—an old friend corrupted by other influences with removed and modified functionality. It was vaguely unsettling.

The thing that immediately stood out to me was the change to the function cons.

In LISP, all lists are made up of cons cells, a core primitive type. Cons cells are basically an ordered pair of elements. There is the first element and the second element. The elements can be anything. Lists are made up of stringing together cons cells. There are various functions in LISP, such as first/rest and car/cdr, that get the first element and the second element. Clojure has its own getters with first and rest, but it doesn’t really have cons.

Clojure does have a function cons, don’t get me wrong. But it doesn’t have cons cells. When you use cons in Clojure, you are not actually making a true cons cell. You are just joining two sequences or an element and a sequence. Clojure lists are not made up of cons cells, and Clojure doesn’t actually have true LISP cons cells in its implementation.

Using cons and first/rest may seem LISP-y, but in reality they are two different animals at a basic implementation level. A practical example of this is that you can’t do (cons 2 4) in Clojure, whereas in LISP it would create a dotted list/cons cell of (2 . 4). You can, however, do (cons 1 nil), making a list of just one, same as Common LISP.

This change was a jarring shift. Same name. Two different implementations. I don’t understand why the makers of Clojure kept cons around if they weren’t going to use it or implement what it represents.

But it is a really minor gripe, all things considered. It wasn’t a dealbreaker. I didn’t give up because Clojure didn’t have cute cons cells. I kept pressing on, learning more about the strange beast that is Clojure.

I figured out that, hey, it may not have cons cells, but it has other nifty data structures with unique syntax. Want to make a hash? Unlike Common LISP you don’t have to do (make-hash-table)—you can just use curly braces! Insane. And very readable.

It was things like that that slowly made all the little minor annoyances between Common LISP and Clojure fall to the wayside. My skepticism chipped away at every neat trick I discovered, at every modern convenience Clojure offered. I accepted the Clojure wasn’t a poor imitation of Common LISP. That maybe, just maybe, Clojure had things to offer that weren't merely parts of LISP dragged into the modern era. I began to understand it.

Clojure is created with Java in mind, yes, this is true. This means that a simple line of Clojure code might create a obscure Java error. But this also means that you can use Java functionality and abuse (or leverage, if you prefer) the power of the JVM, such as the efficient JVM garbage collection. The parts of Java are interwoven into its being, for better and for worse.

But Clojure isn’t all Java. It looks like Common LISP, and acts somewhat like it, but it doesn’t feel constrained by old design choices. It has a unique elegance to it in syntax and style that Common LISP does not have. As I mentioned briefly, Clojure deciding to make different list-style structures have different symbols (e.g [], {}, and so on) can make programming so much easier. These structures do exist in Common LISP, but they feel rather clunky, and, honestly, compared to Clojure, they are more of a pain to deal with. Sometimes I yearn for most everything being wrapped in parentheses rather than sometimes brackets and braces, but the variety is nice and I like being able to make a hash without explicitly saying to make a hash. It is convenient.

That conveniency is where Clojure’s design really comes into play. Clojure is specifically a functional programming language. Common LISP, however, is multi-paradigm. It can do anything you want it to do, for the most part. Clojure is constrained and narrowly focused. It is defined as functional and immutable and that is what it does. With clear goals, conveniency comes.

Another priority of Clojure’s that makes it extremely convenient in this modern era is its focus on concurrency. Instead of an afterthought, Clojure has baked in STM support and slick ways to effectively handle concurrency. No more coordination of packages and patches to optimize for the current age. It is all right there.

The execution of its clear goals and priorities make Clojure a breath of fresh air. There is something very appealing in a language that knows its reason for existence. There are problems with Clojure, of course. No language is perfect. Each one is a tool for a particular purpose and they may or may not be the right tool for the job. For the jobs Clojure chose, I would say it has the strong potential to be the right tool.

All this positivity might be worrying. Did I drink the Clojure Kool-Aid? Did I become one of the Clojure Collective?

Yes.

I assimilated with Clojure.

But I don’t think that’s such a bad thing.