Writing‎ > ‎

A guide to Javaless Clojure

NOTE: This article was written for something other than google sites. It seems that google sites don't import internal links properly, and I may not have fixed them all..


What you'll find here

Clojure is a relatively new lisp variant that's been attracting a lot of attention lately. Part of the reason is that it runs on the JVM, making integration with Java and other JVM based languages, and access to all those nice Java libraries, easy. Unfortunately, this also means that it comes with a lot of the Java infrastructure as overhead.

Fortunately, you can do a lot with clojure without drowning in the Java infrastructure. The goal of this document is to help you set up and use clojure with the minimum amount of Java infrastructure knowledge. If you're already familiar with that Java infrastructure, you're wasting your time reading this (unless you're going to provide feedback, which is always appreciated). If you're not fairly familiar with your computer and it's operating system, you're also wasting your time reading this (with the same caveat).

I'm a Unix user, so that's what's going to be the first options here. Mac users are lucky — Apple switched to Unix a while back, so most of this should apply unchanged. Where that's not true, it'll be noted. Windows users will have more differences to deal with. I'll try to note them, but haven't been able to test them, so corrections are welcome. Sorry about that, but I can't provide information I don't have.

A note on example code: the computer output is always shown in a red color. Variables that you'll need to replace in scripts use THIS font.

As a final note, this document may appear long. That's partly because it deals with multiple platforms and options, but it's also partly because it's not just a howto — I try and explain what's going on, so that when someone has problems I didn't cover, they have a chance of figuring it out and fixing it for themselves.

Java Installation

You have to have a Java system installed. Hopefully, you've already got it. If not, and you're on Unix-like system, your package manager should install it for you. Otherwise, go to OraSuns java download page, find "Java SE", and download and install the latest version of the JDK. You can install other bundles if you want, but the point of this page is that you don't need more than the JDK.

Clojure Installation

The simplest way to install clojure is using your systems package manager, if possible. I don't know what system you have, so I don't know anything about your package manager. If you use Unix and don't know about your package manager, either consult your systems administrator or use the manual install section.

Mac users have a choice of three different package managers: fink, MacPorts, or pkgsrc. Clojure has been reported in the MacPorts system, but I haven't checked myself. Installing some of these may well be more work than just installing clojure manually.

As far as I know, windows doesn't have a package manager, so skip down to the manual installation section.

Package manager installs

Before doing an install with the package manager, check what version of clojure is installed, and then go to clojure downloads page and see what the latest release version is. That is tagged as Featured on the downloads page. If your package manager isn't installing the latest release, then you can either bug the maintainer for that package, or go ahead and do a manual install.

After installing clojure with your package manager, check the list of files installed. You should find at least two files, and possibly more. Most important is clojure.jar. You'll need to note what directory that is installed in, as it is the JARDIR referred to later in this document. There should also be a file somewhere along the path named clojure or clj or something similar, to be know as CLJCMD from here on out. Running that should start the REPL. Finally, there may be a clojure–contrib.jar. If that's there, you're done, and can skip down to editors. If it's not there, then skip to the instructions for installing contrib in the manual installation section.

Manual installation

Clojure

Clojure proper is very easy to install — it's just a java jar file. Download the latest release from the clojure downloads page. This should be the one tagged Featured. Pick a directory to put it in that suits you. Personally, I use ~/.clojure, but you can use ~/lib/clojure or ~/Library/Clojure on a Mac. We're just going to use it as a place to hold jar files; the name isn't otherwise important. I'm going to call it JARDIR in the sequel.

At this point, you can test that things are working properly. At the shell, run the command:


java -cp JARDIR/clojure.jar clojure.main

That should start the REPL. See the section on it for what the REPL should look like. Use Control–D (Control–Z on Windows) to exit it. If that's not what you get, see the problems section.

Contrib

If you managed to install the clojure jar, then clojure-contrib is no harder. Go to the clojure–contrib downloads page and get the version that corresponds with the version of clojure you are using. This should be the latest release. Note that versions flagged as "–RC#" are not releases, but candidates for a release. Avoid them.

After you've downloaded and dearchived the file, copy clojure-contrib.jar to JARDIR alongside the clojure.jar file. If you are installing clojure-contrib after installing clojure with a package manager, you'll want to read the section on the command and possibly tweak the CLJCMD script just a little.

You can test that you've got the contrib library installed properly at the REPL. First start clj with this command (not quite the same as last time):


java -cp "JARDIR/clojure.jar:JARDIR/clojure-contrib.jar" clojure.main
Clojure 1.1.0
user=>

Now, at the user=> prompt, try using the library. That should work something like so:


user=> (use ['clojure.contrib.def :only ['defn-memo]])
nil
user=> (doc defn-memo)
-------------------------
clojure.contrib.def/defn-memo
([fn-name & defn-stuff])
. . .

The use expression loads the defn-memo macro from the clojure.contrib.def namespace, then we use the doc macro to ask for information about it. Use Control–D (Control–Z on Windows) to exit the REPL. Again, if you don't get output that is fundamentally what is shown above, then something is broken, so see the problems section. Otherwise, it's time to make things a bit easier to use.

The command

OK, you've now got clojure installed, along with the contrib libraries, and are ready to start trying to write code. Except if you installed it manually, you have to remember that ugly long java command every time, or if you installed a package that didn't include the contrib library you have a command that doesn't let you use the library. We're going to fix that.

Those of you familiar with Unix scripting (or Windows scripting, for that matter) should have a good idea of what to do next. We're going to create a shell script (bat file) to run the command. If you installed a package, then you already have that. If you're going to create a new one, it looks like so:


#!/bin/sh
java -cp "JARDIR/*:." clojure.main "$@"
    

Note that if you installed clojure with a package manager, the critical change is to the -cp or -classpath option to the java command, or possibly to the CLASSPATH environment variable. For best results, try replacing clojure.jar (or the equivalent) with \*.

For windows, the bat file looks like:


@echo off
java -cp "JARDIR\*;." clojure.main %1 -- %*

This is the simplest thing that should work. The magic you need to understand is the value of the -cp option. This tells java where to look for classes. In particular, we tell it to look in all the jar files in JARDIR with JARDIR/*, quoted so that the * isn't expanded by the shell, and in the current directory (.). The two are separated by a :. Both of those need to work. Save the text in a file called clj or clojure (CLJCMD from here on out) somewhere in your path, then run chmod 755 CLJCMD to make it executable. Try running it with no arguments and verify that you get a REPL. Exit that with Control–D (Control–Z on Windows), and try running the script again with --help as a lone argument. You should get a help text that starts with something like:


Usage: java -cp clojure.jar clojure.main [init-opt*] [main-opt] [arg*]

  With no options or args, runs an interactive Read-Eval-Print Loop

If you get that, congratulate yourself, you've successfully installed clojure. Wasn't that hard, was it? You can go look at the Tweaking the environment section for some pointers on how to make it better. If not, try changing the script to read:


#!/bin/sh
JARDIR="JARDIR"
java -cp "$JARDIR/clojure.jar:$JARDIR/clojure-contrib.jar:." clojure.main "$@"

For package manager installs, we're changing the same value, but this time instead of replacing clojure.jar, we append a :, the directory name again and then clojure-contrib.jar.

For windows, this one looks like:


@echo off
set JARDIR=JARDIR
java -cp "%JARDIR%\clojure.jar;%JARDIR%\clojure-contrib.jar;." clojure.main %1 -- %*

The only change is that you're listing the two jar files explicitly instead of passing a * to the JVM to tell it to find them all, because some older JVM's may not understand the latter. This will make working with other Java libraries harder, but is otherwise pretty much insignificant. If that doesn't work, try the problems section.

The REPL

The REPL (as a reminder, that's the Read Eval Print Loop) is the single most important tool in a lisp programmers tool box. If you're familiar with them, you can skip this section. When it's started, you should have a terminal window displaying something like:


$ CLJCMD
Clojure 1.1.0
user=>

If you don't get that prompt, something is broken, so read the problems section for troubleshooting advice. If not, then you now have the ability to type clojure expressions and see their value, ask for documentation on clojure's builtin functions and macros, and search the documentation for functions. Since clojure functions are defined with clojure expressions, you can write and test functions at the REPL. It's your new best friend — at least when writing clojure.

The most important thing to know about the REPL is that it evaluates clojure expressions, which are either literal values or function invocations of the form (function argument ...), and then prints the value of that expression. Some simple examples are:


user> "Hello World!"
"Hello World!"
user> (println "Hello World!")
Hello World!
nil
user> (+ 3 5)
8
user> (* 8 5)
40
user> 

More immediately useful, you can ask the REPL for documentation on a function or macro that's part of clojure, using the doc function and then the name of the function or macro. Try it now with (doc println). Now ask about + and *. Even better, you can search the documentation with (find-doc "thing"), which will find all the functions or macros that mention thing. If you read the docs on doc and find-doc, you'll see that there's even more power lurking in them.

Editors

As cool as the REPL is, typing programs into it over and over again gets old pretty quickly. So clojure lets you store them in text files. All you need is a text editor with a couple of common features, pretty much any editor will do, so try your favorite first. If your favorite is some fancy IDE, that will almost certainly work.

The first feature is parenthesis matching, meaning you can point out a paired character like (), {} or [], and the editor will indicate where the matching character in an expression that included nested pairs, etc. Or it may indicate an error, if what's inside the pair in question isn't balanced.

The second feature is simple auto indentation, meaning that if you hit newline, it should prepare you to start typing at the same indentation level as the previous line.

If you've got those two, you're ready to write clojure code. If not, you may need to turn them on in your editor. If your editor doesn't have those, you either have to live without them, or change editors. Jedit is a popular cross–platform programmers editor; you might try it. Up to you whether to install it via your package manager or from the web site. Once again, look at Tweaking the environment section for how to make the environment nicer.

Running code

You've got a clojure command that can start a REPL and an editor, so it's time to write some code.

A first script

Try saving the following in a text file called greet1.clj (leave the first line off if you're on Windows):


#!/usr/bin/env CLJCMD

(defn greet! [name]
  (println "Hello" (str name "!")))
  
(greet! (apply str *command-line-args*))

You can now run it using CLJCMD greet1.clj Joe, and it should respond with Hello Joe!. Try using the doc function to figure out what's going on here. One clue: defn defines a function.

If you're on a Unix system, you can make the script directly executable by changing it's mode to 755. The best you can do with Windows is to create a batch file.

Scripts that use scripts

Only small programs fit nicely in a single file — even in a language as powerful as clojure. You can load functions from another file very easily. Try the following second script:


#!/usr/bin/env CLJCMD

(use 'greet1)
(greet! (apply str *command-line-args*))

And then run it with CLJCMD greet2.clj Joe. It prints the output from the invocation of greet! —. Twice. Then it throw an exception, complaining about namespace 'greet1' not found after loading '/greet1'.

OK, the duplicate print is easy to explain: we call greet! twice. Once in greet1.clj, and once in greet2.clj. The other error is the Java camel poking it's noise into our clojure tent. When you use a file, you are actually using a namespace. Java applications — including clojure — find the namespace by looking where it expects the file to generate the namespace in question to be. It found the file, but the file didn't create the namespace, so clojure complains on exit.

To fix this, create greet3.clj that is almost identical to greet1.clj:


#!/usr/bin/env CLJCMD

(ns greet3)

(defn greet! [name]
  (println "Hello" (str name "!")))

We've taken out the invocation of greet! that was in greet1, which will remove one of the output lines. We've also added an invocation of the ns macro to create a namespace called greet3 where the code in our file will be. After changing greet2.clj to use greet3 instead of greet1, run it again. This should just print our greeting.

Note that the use is obsolescent; you should actually use the :use keyword of the ns macro. Either one has much more power than shown here, allowing you to selectively import functions, or exclude them, etc.

Dipping a toe into the Java

Dealing with namespaces

Continuing with namespaces, the Java convention is that the namespaces for your published code should be drawn from the internet's domain name system, only backwards, to prevent clashes with other people's libraries. To comply with that, I would call our scripts above org.mired.greet#.

That's not so bad, but when searching for a namespace, java searches for it in two sets of places. One is inside all the jar files on the classpath (that's the value of the -cp option in our script), and the other is in the directories on the classpath. The catch is that each dot in the namespace translates to a sub directory to look into. So java (and hence clojure) will look for org/mired/greet1.clj instead of greet1.clj if I (use greet1). Working with this with conventional UNIX tools is a pain — you run your commands in one directory, but edit files somewhere else entirely. Java IDEs deal with this for you — it keeps the list of files handy for you to select from. Likewise, Java–influenced clojure tools like leiningen know about this — they'll let you execute or edit a "namespace" and look for it in the right place in the directory tree.

If you're not using a Java IDE, and not planning on publishing your application, I recommend you ignore the convention. Just keep your files in the top level directory and sub directories as you would with a language without that convention.

If you want to use the "conventional" namespaces, but also don't want to deal with the deep directory structures, you can finesse the issue by creating all but the last level of the directory structure, then symlinking that name back to the top. So I have:


bhuda% file org/*
org/mired: symbolic link to `..'

This causes clojure to look for org.mired.foo in the current directory. Source for other org domains will be created normally. If I create a package that has it's own class files in org.mired, then I create a directory in the current level, just like I'd do with any sane language. This may cause problems if I want to create a package whose name matches a top level domain, but I'll live with that restriction in order to be able to keep my files where I want them.

On a related note, if you don't have a domain of your own, you can still publish your code with a conventional namespace. Chances are, one or more of the sites involved in publishing your code will provide an acceptable name. If you're going to publish your application on sourceforge, then appname.sourceforge.net points to a page you can edit on sourceforge; that will work fine. Ditto for username.github.com if you're going to publish on github. If you're going to publish on a blog, there's a good chance it has it's own domain name (e.g. mired.wordpress.comor miredincode.blogspot.com) that you can use.

Failing that, you can just make up something and put your name in it. But you're no longer in a managed name space, so doing something like names.meyer.mike could run into trouble (there are a lot of me out there!) later.

Libraries

Using third party java libraries, fortunately, is much easier than dealing with namespaces. Once you've got the jar file for the library, just copy it into JARDIR. You then access those namespaces in clojure with the import function, or (preferably) the :import keyword of the ns macro.

For example, to use Sun's experimental comm port IO libraries, I put the collection of jar files I download from Sun in my JARDIR, then add an import to my code:

(ns org.mired.commapp [:import javax.comm.CommPortIdentifier])

and then later in the code access it via the Java interoperability capabilities:


  (defn getport [name]
     (.open (CommPortIdentifier/getPortIdentifier name) "output line" 2000))

The one catch is if you're not using the /* version of the clj script. In that case, you have to add each jar file to the -cp option value.

Compilation

You will have noticed that the scripts run really slowly, at least compared to other scripting languages. That's because, well, you have to load the Java vm, then the clojure libraries, then compile the clojure before you can run it. Most of these things weren't designed to be used as part of a scripting language; they were designed to build enterprise systems, where a few seconds of startup time are negligible. However, see Tweaking the environment for an alternative solution.

The obvious solution is to compile your clojure. That doesn't really cut down the time much, though. You still have to load the java vm and clojure libraries. Since clojure compiles the code, all you really need to do is save the compiled code to disk. To do that, make sure you have a classes sub directory in your top level source directory, and the appropriate namespace tree in classes as well, and add (:gen-class) to the ns macro in each file. Finally use (compile 'namespace) to compile the code in namespace. This will create Java class files that will get used if you add ./classes/ to the -cp argument to java in your CLJCMD.

Of course, eventually what you will want is a jar files of your clojure application. That involves compiling the clojure code as above, then using the jar command to create the jar file. This is the point where avoiding Java is no longer simple. You could try using make or a similar tool to drive the process, but you'll still have to deal with the minutia of the jar command. Using the Java infrastructure tools for this isn't noticeably harder than doing it with make and friends. Actually, the same is true for using those tools rather than trying to compile more than a few clojure source files without them. The clojure community seems to be settling on leiningen for these kinds of things, but there is still a lot of support for tools that tools that aren't so clojure specific.

For the record, if you want to bundle just one class, start by making sure the classes directory (above) has only the files from that class in it, then create a manifest.txt file that contains the string "Main-Class: classname" - with classname being the name of the class being bundled. Now run the jar command jar cvfm classname.jar manifest.txt classfiles. The classfiles should be a regexp that lists all the .class files created by the (compile) step. That will create classname.jar, and you can move that to JARDIR and then use it like any other jar library.

The default name for the procudure java will run if you try running just that class is "-main". It will be passed the command line arguments as a sequence of strings.

Addendum: Tweaking the environment

At this point, you have everything you need to start working with clojure. However, the environment is primitive. Following are some things you can do to improve things. They aren't required, but will make life more pleasant.

The REPL

If you're on a Unix system, I recommend installing and using the rlwrap command, either from your package manager or from the author. This provides emacs–style command line history and editing by default, but can be configured to give you vi if you prefer. The CLJCMD script should change to look like:


#!/bin/sh
JARDIR="JARDIR"
if [ "$#" -eq 0 ]
then
    rlwrap --command clojure --quote-characters='"' java -cp "$JARDIR/*:.:./classes/" clojure.main "$@"
else
    java -cp "$JARDIR/*:.:./classes/" clojure.main "$@"
fi

If you're using the version that lists both clojure.jar and clojure-contrib.jar as part of the argument to the -cp option, use that on both lines.

If you're using windows, get the jline library, unzip it and install the jar file and copy it to JARDIR. Then if you aren't using the \* version of the batch script, change it to add the jline jar file, plugging in the right version number:


@echo off
set JARDIR=JARDIR
IF (%1)==() (
    java -cp "%JARDIR\jline-VERSION.jar;%JARDIR%\clojure.jar;%JARDIR%\clojure-contrib.jar:." jline.ConsoleRunner clojure.main %1 -- %*
) ELSE (
    java -cp "%JARDIR%\clojure.jar;%JARDIR%\clojure-contrib.jar:." clojure.main %1 -- %*
)

If the \* version works for you, then you don't need to add jline-VERSION.jar to the command line. That's the advantage of that version.

jline also provides command line editing and history, but configuring it requires wading through the Java class docs. rlwrap works better out of the box, and has a man page, meaning it can be configured without having to wade into the Java infrastructure, and avoiding that is the goal here.

Editors

If you're using a fancy Java IDE, then why are you reading this? You should already be familiar with all the Java infrastructure I'm helping people avoid learning about. But since you're here, check the plugins/modes/whatever they're called in your IDE, to see if it already has clojure support. If so, it should provide better auto indentation, syntax highlighting and maybe better REPL integration. Recent versions of Jedit provide this. If not, or if you're using an editor, google for clojure and your IDE or editor name (but not emacs!). You may well find pages to help you configure them to make writing clojure easier.

If you're using emacs, congratulation. Your help is here. You want to install clojure-mode.el from github. Since emacs is your favorite editor, I'll assume you know how to install such. This should give you smarter indentation, syntax highlighting and the ability to send code to an inferior clojure. You might also consider paredit mode if you aren't already using it. If you're used to using SLIME for dealing with lisp inside of emacs, you may also want swank–clojure to connect them up. If you're not using SLIME, I'd leave it until later. It provides a better environment, but has a history of being painfull to install.

GUIs

I don't do GUIs. A mouse is just to low bandwidth a device for a lot of tasks, and people who want GUI should just boil up a batch of okra. Me, I like my okra fried.

If you've got a Mac, you probably don't agree with me. In that case, there's a tool called Platypus that can wrap your CLJCMD with a clickable icon. The script to use is open -a Terminal CLJCMD. This won't let you double–click a clj file to run it, or drop clj files on your clj script. It will create an icon that will launch a Terminal window running your REPL when double–clicked. Platypus can also be used to turn clojure scripts into clickable icons that generate text or HTML output, or a progress bar, etc.

Once you start getting into the Java infrastructure, you can use jarbundler — also available in some of Suns developer toolkits — to create conventional Mac applications from jar files. Presumably, a similar tools is available for Windows.

Performance

There is one thing you can use to improve the performance of clojure scripts without having to get further into the Java infrastruture: nailgun. This consists of a server — written in Java — that runs in the background, and a client — written in C — that talks to the server. The first time you run a java application on the nailgun server, it will have to load the jar files, but java is already loaded. The second time, the jar files are loaded, so your application starts almost instantly.

To use it with clojure, start the server with the same java command you normally use (without rlwrap if you use that, but with the jline jar if you use that), except use com.martiansoftware.nailgun.NGServer instead of clojure.main. You can then start clojure using ng clojure.main arguments just like you CLJCMD. If you use rlwrap for REPLs, pass it the ng command instead of CLJCMD. If you use jline, then run ng jline.ConsoleRunner clojure.main args to start your REPL.

However, I don't recommend using nailgun for REPLs. Those tend to be used during development, so broken things you defined in the user namespace will persist across sessions — meaning you can't just start a new session to clear out all the development code! Given that REPLs tend to be around for a while, the startup overhead is minimal compared to this problem. For scripts, on the other hand, you reload the script file each time, so that's not an issue, and the time savings from not loading java and jars needed can be significant.

Problems

As a first step, try and go back over the process so far and figure out what's wrong. Some things to try include making sure that the shell (.bat on Windows) script and java executable are in your path and flagged as executable. Double check the expansion of JARDIR in the script, and that the * is properly quoted there as well.

If none of the above helps, read the smart questions writeup if you haven't read it before. Finally, record what you've done so far, what you did that doesn't return the right result, the result you expected, and the result actually got. Send that to clojure@googlegroups.com. That's preferable to contacting the author - he'll read it there as soon or sooner than he would if you send it directly, and someone else may get you an answer even faster.

Comments

Follow our lead!