- cross-posted to:
- lisp@programming.dev
- cross-posted to:
- lisp@programming.dev
A Clojure implementation on Chez Scheme. Self-hosted compiler, Clojure-compatible standard library, no JVM.
(yooo Awesome project!!!)
Thanks! It’s been pretty fun working on it, and starting to get to a state where you can actually do useful things with it. :)

@yogthos@lemmy.ml, I’d be interested in a blog post of your thought process on 1) taking up this project given how many Clojure dialects are already out there, and 2) why you chose Chez Scheme as the host. I imagine you considered Racket as well, since it’s also hosted on CS, which would mean you had to weigh Racket’s “language-oriented language” features against a panoply of other factors.
Sure, I can answer some of that here. The motivation is that I wanted to see how hard it would be to make a Clojure dialect that could run existing Clojure libraries for the JVM. My intuition was that most of them use a fairly small chunk of the Java standard library, and if I shimmed out stuff like IO and a few other things then stuff should just work. Turned out to be a bit more work than I anticipated, but a lot of the libraries now really do work same as on the JVM. And the bonus here is that I was able to run the full test suites for the libraries on Jolt and verify they really do behave as intended.
The problem with any Clojure dialect is ultimately in building out the ecosystem around it, and you tend to get a chicken and egg problem as a result. Being able to use a lot of the existing libraries out of the box largely side steps the issue. Aside from what I’ve shimmed out in the core language, it’s also trivial to make your own adapter library providing whatever shim you need if you want to get an existing Clojure library running that requires some other part of Java standard library. So, migration process is fairly painless.
Java runtime evolved in an era of enterprise architecture, designed for massive application servers like Tomcat or WebSphere which were effectively their own operating systems. In that model the application server would greedily consume all available host memory and run continuously for months on end, making long JVM startup phases and heavy initial resource footprints perfectly acceptable trade-offs. But that monolithic design is completely at odds with how modern web applications are typically built, especially in fast-paced startup environments where the engineering culture has shifted toward microservices. Today, you typically want to deploy fleets of isolated containers that boot instantly and can dynamically scale horizontally to handle sudden traffic spikes.
The main reason for using Chez is that it provides IR along with JIT and generational GC. The last is really important since Clojure creates a lot of short lived objects with its persistent data structures. Chez is also pretty compact, and you can get a standalone binary for Jolt under 10 megs with it. Incidentally, Racket is itself built on Chez, so I do have compatibility with it as well. Also worth noting that choice of Chez is incidental from user perspective since Jolt has its own standalone binary and doesn’t require Chez to be installed to work.
And that brings us to the second benefit which is having access to Chez, Racket, and all the native C/C++/Rust libraries. For example, I made a Reagent style library on top of GTK, and have a TodoMVC example using it here. You can just develop a native UI using nREPL, and have it reload live when you make changes. I even have a full on Quake style FPS demo working with it.
Performance is already decent beating Java in some cases, being 1~2x in most, and around 7~8x in the worst case.



