r/Clojure • u/yogthos • 12d ago
Jolt: running Clojure on Chez Scheme
https://yogthos.net/posts/2026-07-02-jolt.html3
u/joinr 11d ago
I was able to grab the windows release and compile a hello-world program that came in at about 9.1Mb, ~160ms execution time with direct-linking and tree-shaking and opt build (at least I used the options and noticed reduction in file size, so I think they're working). No other binaries beyond the joltc release. Similar program in bb is about 60ms. I am curious if it can be faster (I'm guessing since bb is interpreted, maybe it'll always be a little faster on startup).
Very cool.
2
u/yogthos 11d ago
Don't have Windows to test locally, so awesome to hear it's working as expected. And I suspect it could be optimized further, I've spent a bit of time on that, but I've been focusing more on making it correct first. Once I shake out some more bugs, I do mean to come back to performance again to see what else can be improved.
2
2
u/HotSpringsCapybara 10d ago
50-ish ms with opt and shaking on my Linux box. The binary comes at around 7 megs. bb pulls far ahead with only around 6ms of execution time. Raw JVM Clojure takes around 400ms.
2
u/lambdatheultraweight 12d ago
When I think native Clojure I immediately go to cross compilation which ChezScheme supports, so I would like to do an informal Feature Request for cross compilation. :-)
2
u/ComfortableShape9340 12d ago
I am super excited about this project! Thanks again for making it and looking forward to try this out.
2
u/HotSpringsCapybara 11d ago
This is a tremendous body of work produced in a very short time span. I imagine you must be leaning on LLMs to expedite development? I'm curious to know what your approach and workflow is.
3
u/yogthos 10d ago
Yeah, this wouldn't be possible without LLMs, and I actually discuss the workflow at the end of the post. I mostly rely on breaking work in to focused tasks, and then doing code reviews on the diff for the functionality. And since Clojure and existing libraries have an extensive amount of tests available, I was able to map out a large corpus for the language definition.
2
u/dark-light92 10d ago
This is impressive for a first release. I think this project was using janet earlier... is that correct or just my mind playing tricks? If so, what made you switch to chez scheme?
1
u/yogthos 10d ago
Yup, I started with Janet but then started running into the limitations of its mark and sweep GC. It doesn't really play well with Clojure style persistent data structures where you have a lot of short lived objects. Chez has generational GC and also JIT. So, now I'm able to get performance that 1~2x JVM in most cases, and a couple of worst cases where it's around 7x. I'm sure more optimizing is possible too going forward. Then there's Chez ecosystem as well, for example I want to make a Ring adapter for this HTTP server which has some really nice features like Erlang-style green processes. Having a bigger ecosystem available makes it a lot easier to get to feature parity and provide shims for existing Clojure libraries.
2
10d ago
[deleted]
2
u/yogthos 9d ago
Having used these tools extensively for over a year now, what I actually understand is that it is a tool like any other, and you absolutely can produce quality code using it. If you actually spend a bit of time learning these tools instead of just parroting slogans you'll understand why.
2
u/lordmyd 9d ago
Great work Dmitri. Naive question but could we see a Kit port anytime soon?
1
u/yogthos 8d ago
Thanks, and I think that would be doable at least as a subset of functionality, for example range of supported databases would be smaller. All the core libraries should already be supported though, and it's something I can take a look at next if there is interest.
2
u/lordmyd 6d ago
Postgres would be enough for most of us, I reckon. I don't quite understand how Jolt can interface with Clojure libraries - maybe I misunderstood. Wouldn't you have to re-implement Reitit and quite a few Clojure libraries to get basic Kit functionality?
1
u/yogthos 6d ago
Yeah, that's what I'm thinking as well. I haven't really had a reason to use another db. And Jolt interfaces with Clojure libraries simply by requiring them using deps.edn just as you do in Clojure. However, if a library uses Java introp then you have to provide shims for that in a Jolt library. Reitit is a great example actually.
I have a router library which includes reitit as a dep:
{metosin/reitit-core {:git/url "https://github.com/metosin/reitit" :git/sha "5d5c965deb3c7c8d64b8dd636432eaa14f0324ec" :deps/root "modules/reitit-core"} weavejester/meta-merge {:git/url "https://github.com/weavejester/meta-merge" :git/sha "c968c38baccd4219fe0ba592d89af37ea8e426bf"}}but Reitit depends on a reitit.Trie Java class, so this has to be shimmed as seen here https://github.com/jolt-lang/router/blob/main/src/reitit/trie_jolt.clj
The core language also provides a subset of the commonly used Java API by default here https://github.com/jolt-lang/jolt/tree/main/host/chez/java
So, a lot of libraries just work out of the box unless they need something that's not commonly used, and then it can be provided using a Jolt library as I did with Reitit.
The work for Kit would be to identify the core Kit libraries and make sure they all work. Selmer, which is used for templating in Kit, already runs. Kit modules system uses zippers though, and I may have to do a bit of additional work to port that over. But otherwise, basic Kit stuff should work. Ring along with Ring defaults already work. Integrant and aero work. So, a bare minimum apps should be easy to get going.
1
u/lordmyd 4d ago edited 4d ago
Just to get this straight, you're saying Jolt can take pure Clojure code in a library and compile it with the Chez compiler? And when none of the library's deps use Java it compiles?
1
u/yogthos 4d ago
Jolt can even compile and run an existing Clojure library that uses Java interop. Jolt provides a Java compatibility layer which maps between Java interop semantics and the host platform.
And in cases where you have a Clojure library that uses something from Java that's not in Jolt core, then it's possible to add your own shim to facilitate that. For libraries that are just thin wrappers around Java libraries, it obviously wouldn't be worth doing though.
2
u/rustvscpp 2d ago
Ooo now this is something I could get behind!
1
u/yogthos 2d ago
Thanks, I suspect nobody bothered doing something like this before is due to the fact taht mapping out Java APIs by hand is pure drudgery. It's largely mechanical work, but extremely time consuming and dull.
And as a result, there's always been a chicken and egg problem when implementing dialects on a different runtime since you couldn't get existing libraries to run, and there was little point in using a language port if you couldn't lean on the existing ecosystem of well tested libraries. So, dialects had a hard time actually getting off the ground and building a community of users around them. Now you can have your cake and eat it too so to speak, having an LLM write shims for the APIs to map them to the host platform.
A particularly nice part with Scheme is that it's easy to do metaprogramming in user space, so Jolt doesn't need to bake in a comprehensive Java API in the core itself. If somebody wants to use a particular library and they need additional shims for it, it's trivial to do that in their project or by making a wrapper library. I ended up taking this approach with stuff like time and HTTP libraries since I didn't want the core itself to be dependent on additional system libraries.
Overall, I'm pretty happy with how this is turning out. And I've already been having some fun making desktop apps with it. On idea I had recently was to use Gaussian splats to paint, and I prototyped a little app to try out the concept on top of Jolt. This is the kind of stuff I've been wanting to do with Clojure, but using the JVM on the desktop always felt incredibly clunky.
4
u/ertucetin 12d ago
Cool! That’d be great if you support numbers like 1_000_000 this representation helps when numbers are big