Clojure was originally designed to be a hosted language. What this meant was not really clear to me when I first heard about it. I was using Common Lisp, which was not meant to be hosted. A lot of the things that made Common Lisp a great language were not available on the JVM. For instance, Common Lisp features a much more complete exception system and it has tail call elimination. So I had all of these questions about how you would implement those if you had to run hosted on the JVM.
But it turns out that Clojure doesn't have those features. There was no attempt to add those features to Clojure. This was a really weird decision to me. I've used the Java for a long time and always missed these great Lisp features. But after using Clojure for a while, I started to see the elegance of relying completely on the host platform for what it is good at.
An existential crisis
It brings up a really deep question: what is Clojure if it can be implemented on different platforms with different capabilities? What is incidental to the platform and what is essential to Clojure?
First of all, Clojure has lexical closures. That is certainly an important part of functional programming and one of the reasons we like Clojure. And the immutable data structures are, of course, essential: the maps, the vectors, the sets, and the linked lists. Add to that a way to directly access the host and you've got something really special: functional programming on whatever platform you like.
When Java came out in the 1990s, it had a motto that promised ubiquitous computing: Write Once, Run Anywhere. Sun Microsystems was trying to create a language for the internet. It abstracted away OS differences by providing consistent filesystem access, networking APIs, and even GUI capabilities. They also created a code security model so that you could safely run code from other machines.
Sun's original mission was not really successful. Perhaps it was ahead of its time. But the Java language and the JVM found a lot of success on the server side, especially at larger companies. Java became synonymous with enterprise software. The JVM as a platform became a stable base for building large software systems on top of. Big companies stopped thinking about OSs as relevant platforms. The OS had been modularized and the language platform became a policy requirement.
It was in this environment that Rich Hickey chose to target the JVM as the host for Clojure. As a Lisp programmer, my heart was broken. Java seemed like a bitter compromise. But as a Java programmer, I immediately recognized the value of the huge number of libraries, the billions spent on infrastructure, and how every many hundreds of millions spent optimizing the garbage collector and JIT compiler.
Of course, there is a cost to the JVM's advantages. The JVM has its own quirks. There are a ton of things to learn, like the CLASSPATH, deployment options, the huge standard library, and the particular semantics of the object model. A lot of people have found the JVM to be a deal-breaker, even for those who would otherwise love Clojure. The Clojure community is poorer for that.
Some people love Clojure and so have chosen to brave the unknowns in the JVM. Unfortunately, they don't know where to turn. Otherwise competent developers find themselves in alien territory. Their intuition fails them. They don't know where to turn. They don't know what level of abstraction is the culprit: their code, Clojure, or the JVM.
While many people worry about switching from an OO to FP mindset, that may not be as significant as learning a platform as big as the JVM. FP and OOP are not so different and a little immersion can go a long way to help you make the switch. It's a simple change in paradigm. Paradigms have guiding principles and are fairly regular. After some practice, the whole paradigm shift can happen in a flash. It's still hard work, but it's just practice.
But compare that to the quirks of the JVM platform. There are thousands of things I know about the JVM just from having written a lot of code in it. These are not things that follow some guiding principles. They're hard-won knowledge, gained one piece at a time. I'm talking about how to scan Javadocs for the information I need. I'm talking about the quirky command-line switches for the JVM. I'm talking about the behavior of the JVM classloader. I'm talking about the difference between InputStreams and Readers. The fact that there are so many unconnected things to learn means they can only be learned one thing at a time.
That's why I created the JVM Fundamentals for Clojure course. I wanted to distill down the most important things to know about the JVM so that you can actually get the awesome benefits of Clojure's host. The JVM is a big thing to learn, but with a little guidance, you can get through that difficult period more quickly and start enjoying Clojure.
The JVM doesn't have to be a huge obstacle to writing Clojure. If you buy the course and follow it, you'll have over five hours of video discussing all of the important things you'll encounter while working in Clojure. The other option is to buy a membership, which includes that course and all of the other courses for learning Clojure.
Clojure is definitely a better tool for some jobs than Java. That's not that interesting of a statement. But what is interesting is that Clojure is sometimes a better Java. That is, even if you're doing imperative, object-oriented object construction and method calls, Clojure is often more concise, clearer, and less error-prone. That's what we'll talk about next time.