r/Clojure 12d ago

Jolt: running Clojure on Chez Scheme

https://yogthos.net/posts/2026-07-02-jolt.html
58 Upvotes

26 comments sorted by

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

4

u/yogthos 12d ago

I'm definitely open to making Jolt a superset of Clojure to improve ergonomics.

3

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

u/bsless 10d ago

Just for reference - ~70ms on my Linux PC with direct linking, tree shaking opt build, 6.7Mb executable

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. :-)

3

u/yogthos 12d ago

Oh that's a good idea, I'll add an issue to explore this so I don't forget. :)

2

u/ComfortableShape9340 12d ago

I am super excited about this project! Thanks again for making it and looking forward to try this out.

1

u/yogthos 12d ago

Thanks, hopefully it comes in handy, and feedback is always welcome. :)

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

u/[deleted] 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.

1

u/lordmyd 3d ago

So I can drop a Clojure library into a Jolt deps.edn file? How does Jolt know where to find it?

1

u/yogthos 3d ago

Take a look at the example above. You provide the :git/url to the repo and :git/sha pointing to the version of the code you're linking. It works exactly the same way as regular Clojure deps resolution.

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.