For me the most interesting part is how it gets rid of the JVM startup time.
So there are two parts to the solution: The first part is Small Clojure Interpreter (sci) which is a "(subset of) Clojure written in Clojure", so kind of McCarthy for Clojure. A cool project in itself but it still needs a VM to run.
So here is where the second part comes in: the GraalVM produces native binaries from various things, including Clojure code and SCI is simple enough to work with GraalVM.
It's cool how these two pieces of tech combine together to create something greater than the sum of the parts.
However, the elephant in the room (which I also like to ignore as a Clojure enthusiast) is that the start up time of a Java based GUI app is too slow (this is exacerbated even moreso when Clojure is involved)
I'm expecting a GraalVM rejoinder from someone. For anyone who's used GraalVM (particularly with Clojure) - what are the downsides and limitations?
If you think that the JVM is icky, GraalVM may satisfy some of your concerns.
Just getting access to Clojure on Windows through a single graal executable saved me some heartache this week, and I can't wait to start packaging apps with it.
I've only done one project with GraalVM and I've been pretty happy with it in regards to faster startup time.
I was doing stuff in Clojure. Clojure is a great language but it tends to have very slow startup times, even by JVM standards (it's not weird for a large Clojure program to take 5-6 seconds to start. Even a "hello world" can take upwards of a second or two). Graal mostly Just Worked with the standalone uberjar produced by Leiningen and created an executable that started in about 3 milliseconds. It was amazing.
While the lack of proper reflection support was a little annoying, it actually wasn't as horrible with Clojure as you might think; most problems were fixed with basic type hinting, and all but one Clojure library I used (http-kit) worked flawlessly.
Back when I wrote Clojure professionally, using GraalVM to generate a native executable of things like clj-kondo basically eliminated the startup latency.
Sometimes the trade-off of slow startup vs. having a JIT'ed VM is better, since you get a lot more performance, if you're working w/ long-lived processes.
This is a good example of where Graalvm's native image is interesting. This is a CLI tool that lets Clojure developers create scripts that are as fast as bash scripts. Clojure may well not be your bag, but stay with me - we're talking about CLI or TUI's written in Java (or a java-based language) that are easy to distribute as statically compiled binaries.
Perhaps someone already mentioned it here, but GraalVM lets you interop between Java and anything LLVM, and therefore Rust, without the JVM startup cost, with breakpoints across languages, even (as I understand it). Compile time is long, though.
borkdude has been releasing for some very cool stuff using this stuff. Here's a Clojure/Rust combo:
Oh! That's a valid reason; I'm actually surprised that GraalVM has issues not supporting JVM features, since I've been using it for Clojure code locally (though admittedly just for fun, nothing serious). Definitely makes sense if you're stuck rewriting things anyway, might as well just do it in a more modern language.
As a side note, GraalVM is quite usable for real world stuff nowadays. Here's an example of running a Clojure web service with Graal that provides JSON endpoints, talks to the database, and does session management: https://github.com/yogthos/graal-web-app-example
The same app can be run on the JVM or compiled statically using Graal. The JVM version takes around a 100 megs of RAM, and has a significant startup time. The Graal version weighs in at 7 megs, and starts up instantly.
Have you tried Clojure with the GraalVM native-image? I am curious to what extent native-image can delete the overhead of Clojure and make fast natively compiled binaries.
With GraalVM you can compile JVM languages to small executables with limited memory consumption. It's fairly new technology but people are using it in production.
TLDR for others: GraalVM lets you compile your code to native, which makes startup times 1000x faster and memory footprint 10x lower. This is great for things like "java/clojure based command line tools", and maybe even micro services. Long running processes on the JVM are about 2x faster than a GraalVM compiled program, so it won't make your normal backend any faster. This is because JIT is better since it can understand how your program is used when selecting which types of optimisations to apply. Also GraalVM doesn't support everything in the dynamic class loading and reflection space.
I haven't touched GraalVM in a couple years, but the big-ish project that I did with it in Clojure was mostly painless, except for the fact that I had to use type-hinting a lot more frequently, due to the reduced reflection capabilities of GraalVM.
So there are two parts to the solution: The first part is Small Clojure Interpreter (sci) which is a "(subset of) Clojure written in Clojure", so kind of McCarthy for Clojure. A cool project in itself but it still needs a VM to run.
So here is where the second part comes in: the GraalVM produces native binaries from various things, including Clojure code and SCI is simple enough to work with GraalVM.
It's cool how these two pieces of tech combine together to create something greater than the sum of the parts.
reply