Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Notes on Common Lisp VS Clojure

Interactive development

I have semi-frequent occasion to work in Clojure, but Clojure lacks some features of Common Lisp that I consider important. The most important of these is that Common Lisp, like Smalltalk, but unlike most other languages, including Clojure, is designed from the ground up to support developing a program interactively while it runs. I want to see if I can have Clojure for those cases where it's the right tool, without losing the programming-as-teaching features of Common Lisp that I miss when working in other languages.

I know someone is probably going to object that Clojure, too, is designed to support interactive development; my answer is: no, it isn't. Not in the sense I'm talking about.

As an example of what I mean, consider the standard Common Lisp generic function UPDATE-INSTANCE-FOR-REDEFINED-CLASS. This function is part of a standard protocol in Common Lisp that enables your program to automatically update existing instances of previously-defined classes to properly conform to a changed class definition.

As I've observed elsewhere, the existence of this standard function is not an accident or an eccentricity, even though it makes no sense in most languages. It makes sense in the context of Common Lisp because the normal mode of development is for your work in progress to be running while you work on it, and no experienced Lisper would expect to have to restart the program or reload code just because they redefined a class. The designers of Common Lisp made this protocol a part of the language standard because they took for granted that the normal way to work on a program was to alter its definitions while it ran, and took for granted that you should reasonably expect the program to continue to work properly while you were doing that.

In other words, the language is designed from the ground up to support interactive programming. Smalltalk is designed with a similar set of assumptions. Most other languages, not so much.

After looking at the quite old benchmarks, ABCL seems to perform alright. Can anyone share their experience with ABCL in terms of performance, stability and memory usage?

I wish I could give you more concrete numbers with an application you could test and see for yourself. Since I can’t do that, I will tell you about my recent work with ABCL. I ported a small Clojure server-side utility to ABCL and can qualitatively tell you that the performance was close to Clojure. After profiling the ABCL version, I believe I can attribute the differences to ABCL’s use of Java reflection for its Java FFI.

I’ve already been successfully deploying Clojure-based applications professionally, and as I’ve gotten more into Common Lisp, I’d like to start deploying Common Lisp based applications as well. I recently posted a patch to the ABCL mailing list and got a very quick response from the maintainer. I really like the quality of the ABCL code base. The compiler itself was very approachable and easy to understand.

I think ABCL really is a worthwhile target in the Common Lisp world because:

Painless Java FFI. You avoid all the instability and signaling issues that crop up when using the JVM combined with SBCL or CCL. If you make a lot of calls, native Java is always going to be faster anyhow than calls over JNI (which is more comparable to reflection).
Use large heaps without worry. Part of the benefit of the JVM is its proven ability to have huge heaps (I’ve been part of projects that had 64GB+ heaps (though honestly I’d rather stay small)).
JVM platform is well supported and tested on a number of OS and hardware platforms

SBCL uses conservative garbage collection and I’m curious how well it would handle really large heaps. CCL uses precise garbage collection but again, I’d like to know how it handles really large heaps. In general, I want all my applications to run with heaps that are naturally in CCL’s or SBCL’s sweet spot, but I’d love to know I could use ABCL if I really ever needed huge heaps. I’m really getting into Common Lisp because I really like the implementation choices. Having a solid Java FFI unfortunately is usually a requirement in my workplace.

To me, ABCL will be /better/ than using Clojure if ABCL’s Java FFI moves away from reflection (when possible). This will close any performance gap with Clojure for most applications. I think this can be done relatively easily in the current ABCL implementation, and I have an idea of how to do it but unfortunately have had no time lately to devote to it. The reason I say “better than Clojure” is that I can write applications that target both ABCL and SBCL/CCL – I can abstract away my Java APIs if I really have to have them (or use LispWorks with a solid Java FFI if I don’t need a ton of Java interoperability). Then when I need fast startup time or low memory footprint, I can use these other CL implementations which are much better suited to it.

The main benefit where I still see Clojure having an edge is if you need a heavy JS-based web interface. I’m not a JS developer, but I was able to successfully use Clojurescript and make a nice looking web application that had pretty seamless interoperability with my Clojure-based server.

Anyhow, I hope this helps you. ABCL is great, I have been very impressed with it and I encourage you to try it out.


"the tooling for most CL implementations is just plain light years ahead of Clojure"

For Clojure the interactive debugging experience is just plain dreadful and for a dynamic language this is pants on head crazy imo. For me a dynamic language has to have a good interactive debugging experience because you have foregone the support of a static compilation and instead wish to reason about your program at runtime. But with the JVM stack traces and lack of interactive debugger Clojure just does not support you in this regard. And as a side note the lack of an identity print is annoying as well e.g. (+ (print 4) (print 4)) "4" "4" 8 (yes, it's easy to add...)

Clojure's decision to use persistent data structures is good but it's really the only standout thing for me other than some syntax sugar like hash maps.

from (2017)

Thoughts on learning Clojure and Common Lisp in 2019 (and some other stuff)

Clojure: It’s a really cool language with a stable core — but there are some issues that make it difficult to get into and sometimes it feels hard to do what you want to do and slower than you would want it to be.

Common Lisp: CL is very fun to program with. It’s very stable and mature ecosystem. If you use sbcl + portacle getting started is basically 5 minutes. I definitely recommend common lisp as an entry point to lisp.

Clojure annoyances (2016): memory hog, slow startup, deal with Java, awful backtraces, not always expressive, heavy setup, docstrings require an extra line

Every time this is brought up there are arguments that Clojure and the JVM alone don’t use too much memory. But once lein is starting an nREPL for a non-trivial project, you’ll want to have a 16+ GB machine. The situation would be even worse if you use a heavy IDE (like IntelliJ or Eclipse). […] So if you’re not careful, you’ll want to limit yourself to running one project at a time.

Clojure starts up quickly (relative to lein, anyway). But the full lein environment is taking me 17+ seconds in a default Luminus project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment