With this post, we round off this series on JVM languages–in the future, we hope to get around to other interesting programming tongues that we missed this time. The last one we checked out was Fantom, a bit of a move away from the traditional JVM langs, and in that spirit we will talk now about Clojure, a Lisp-like programming language that runs on the JVM.
Clojure first appeared in 2007 and is relatively new compared to more established languages. It was created by Rich Hickey as a Lisp dialect targeted for the JVM.
Version 1.0 appeared in 2009 and the name is a pun on C (C#), L (Lisp) and J (Java). The current version of Clojure is 1.4. Clojure is open-source (released under the Eclipse Public License v 1.0 – EPL)
As with the other post, I ported from Java a simple file-based HTTP server that you can download on Github.
Starting Clojure development with Leiningen
After starting reading the Clojure documentation, I decided to setup my development environment using Leiningen which is a Maven like tool for Clojure. Leiningen (or Lein for short) can perform most tasks for Clojure that you would expect from Maven such as:
- Create a project structure (think: Maven archetypes)
- Handle dependencies
- Compile Clojure code to JVM classes
- Run tests
- Publish built artifacts to a central repository
If you have used Maven, then you will feel right at home with Lein. In fact, Lein even supports Maven repositories. A major difference between the two however is that the project file in Lein is written in Clojure itself while Maven uses XML (pom.xml).
I have to admit that Lein was a very welcome addition and although it is possible to develop in Clojure without it, it really makes several things much easier.
So I did the following in order to get the project skeleton:
$ lein new clojure-http-server
Looking at IDE support
After I got the basic project structure in place, it was time to start editing code. As a long-time Eclipse user, the first thing I did was to search for an Eclipse plugin that handled Clojure. This would offer me syntax highlighting and code completion in my familiar workspace. That’s how I found the Eclipse plugin for Clojure called CounterClockWise. So I installed the plugin and created a new Clojure project in Eclipse.
While this was OK, I didn’t manage to import into Eclipse my existing Clojure project that I had created from the command line with Lein as described into the previous section. I expected the CounterClockWise plugin to function like the Maven Eclipse plugin where there is two-way interaction between the pom.xml and the Eclipse GUI.
So, in summary I expected more automatic integration between Lein and the Eclipse plugin.
I also looked at Clooj, which is a lightweight IDE for Clojure developed in Clojure itself. While it is very easy to download and run it, I found it very lacking compared to Eclipse.
In the end I decided to develop in Clojure the hard way using just Lein from the command line and my trusty GVIM as a text editor. I did this because I was very interested to see how Lein works in detail.
I did not find a built-in Clojure mode in Vim (an external plugin file exists), so I just used the Lisp mode which worked well for my needs.
The Read Eval Print Loop (REPL)
Like most Functional languages, Clojure offers a command line shell where you can directly execute Clojure statements. This shell is very handy for development since it allows you not only to test small code snippets but also to run only parts of the program during development.
This is nothing new for developers who have already used languages like Python or Perl. But for Java developers its brings a refreshing and more interactive way to coding.
Functional programming – a different way of thinking
Clojure is a functional language very similar to Lisp or Scheme. The functional paradigm is very different for those who are accustomed to the Java way of OOP and working with side effects all the time.
Functional programming promotes:
- Little or no side effects
- Functions that always return the same result if called with the same argument (and not methods that depend on the object state)
- No global variables
- Functions as first-order objects
- Lazy evaluation of expressions
These features are not particular to Clojure, but rather to functional programming in general:
(defn send-html-response "Html response" [client-socket status title body] (let [html (str "<HTML><HEAD><TITLE>" title "</TITLE></HEAD><BODY>" body "</BODY></HTML>")] (send-http-response client-socket status "text/html" (.getBytes html "UTF-8")) ))
Clojure offers excellent interoperability with Java libraries. In fact, for some basic classes Clojure does not even provide its own abstractions, instead you are expected to use the Java classes directly. In this HTTP server example, I borrow classes such as Readers and Writers from Java:
(ns clojure-http-server.core (:require [clojure.string]) (:import (java.net ServerSocket SocketException) (java.util Date) (java.io PrintWriter BufferedReader InputStreamReader BufferedOutputStream)))
Creating Java objects and calling them is very straightforward. There are actually two forms (as explained in this excellent Clojure introduction):
(def calendar (new GregorianCalendar 2008 Calendar/APRIL 16)) ; April 16, 2008
(def calendar (GregorianCalendar. 2008 Calendar/APRIL 16))
(. calendar add Calendar/MONTH 2)
(. calendar get Calendar/MONTH) ; -> 5
(.add calendar Calendar/MONTH 2)
(.get calendar Calendar/MONTH) ; -> 7
Here is an actual sample:
(defn get-reader "Create a Java reader from the input stream of the client socket" [client-socket] (new BufferedReader (new InputStreamReader (.getInputStream client-socket))))
However for some structures I decided to use the Clojure way. The original Java code uses StringTokenizer which goes against the pure functional principle of immutable objects and no side effects. Calling the
nextToken() method not only has side effects (since it modifies the Tokenizer object) but also returns a different result when called with the same (non-existing argument).
For this reason I used the Split function of Clojure which is more “functional”:
(defn process-request "Parse the HTTP request and decide what to do" [client-socket] (let [reader (get-reader client-socket) first-line (.readLine reader) tokens (clojure.string/split first-line #"\s+")] (let [http-method (clojure.string/upper-case (get tokens 0 "unknown"))] (if (or (= http-method "GET") (= http-method "HEAD")) (let [file-requested-name (get tokens 1 "not-existing") [...]
Clojure was designed with concurrency in mind from the beginning and not as an afterthought. It is very easy to write multi-threaded applications in Clojure since all functions implement by default the Runnable and Callable interfaces from Java allowing any method to run into a different thread on its own.
(defn new-worker "Spawn a new thread" [client-socket] (.start (new Thread (fn  (respond-to-client client-socket)))))
Order of methods matters
One thing that I noticed is that the order of methods inside the source file is critical. Functions must be defined before they are first used. Alternatively, you can use the declare special form to use a function before its actual definition. This reminded me of the C/C++ way of doing things, with header files and function declarations.
Clojure offers a great platform for those looking for a functional language running on the JVM. Developers with experience in Lisp/Scheme will feel right at home. However Java developers will not only face a new syntax but also a new paradigm.
Although it would be possible to abuse Clojure and write code in a Java-like way, this is not optimal. The big strength of Clojure can be found in the concurrency constructs which could be handy in the future as more programmers are interested in parallelization of their code.
Psst! If you liked this post, we wrote a 50-page RebelLabs report on Java 8, Scala, Groovy, Fantom, Clojure, Ceylon, Kotlin & Xtend.
[publication id=”48″ label=”Get the FULL REPORT on all 8 JVM languages”]