let-go v1.12.1 is out 🎉
#C04DCFZKPJN is a Clojure implemented in Go, a bytecode compiler and VM (). *One 13MB binary, 10ms cold start.
This is the first release I've announced here since the launch in May, so let me catch you all up!
• @nnunley and @U0BFC3G163G joined the project as regular maintainers.
• Almost three busy months, five releases, 184 merged PRs, new contributors: @ingy @abogoyavlensky
• New targets: WASI (`wasip1`), improved Plan 9 terminal handling, comfy Web Browser interop in WASM,
• TCP networking and bencode codec, Ring-compatible handler, core.async edge cases fixed
• Dozens of Clojure-compat fixes - it runs real Clojure libraries, unmodified.:
◦ Stock https://github.com/seancorfield/honeysql loads and passes all 10 of its official examples with zero edits. Thanks @seancorfield for kicking the tires!
◦ https://github.com/weavejester/medley, https://github.com/weavejester/hiccup, https://github.com/metosin/malli, https://github.com/weavejester/integrant, https://github.com/juxt/aero, and https://github.com/clojure/tools.cli all run too - there could be more...
◦ If you maintain a Clojure library or framework: We'd love it if you tried it with let-go and shared your thoughts!
• Still passes all 5621 assertions in https://github.com/jank-lang/jank's #C0A2CQQQVPB
() We've also built a *brand new AOT compiler, in let-go itself. Alongside the bytecode VM w now have an IR-based optimizing compiler that lowers let-go to Go. It's about 10k lines of let-go compiling itself to Go. The new AOT pipeline produces static native libraries and binaries deployable to variety of targets. It also brings massive performance gains:
• (fib 35) goes from 2.42s to 0.11s,
• tak from 2.40s to 94ms,
The interpreter got faster too. https://nooga.github.io/let-go/perf/.
• The VM is 39% faster than the v1.8.0 baseline with no regressions.
• Cold boot crept up from 7ms to 10ms as we picked up features, but still qualifies as zippy.
Finally, a new ecosystem is forming! let-go has users and uses...
• @abogoyavlensky built https://github.com/abogoyavlensky/lgx, a project and package manager for let-go and been shipping real tools with it: https://github.com/abogoyavlensky/tiny-cli, https://github.com/abogoyavlensky/tiny-tui, https://github.com/abogoyavlensky/nrepl-client, https://github.com/abogoyavlensky/nreplctl, https://github.com/abogoyavlensky/wtr, https://github.com/abogoyavlensky/skl.
• @U0BFC3G163G is https://github.com/mparrett/let-go-lab with browser and terminal apps,
• @nnunley made a https://github.com/nooga/let-go/tree/main/examples/browser-inspector and got https://github.com/yaml/yamlscript with @ingy,
• I made https://github.com/nooga/legmacs - an Emacs-inspired terminal editor written and scripted in let-go,
Give it a try:
brew install nooga/tap/let-go
Release notes: https://github.com/nooga/let-go/releases/tag/v1.12.1
Repo: https://github.com/nooga/let-go (please ⭐ it, we live for ⭐s)
I'd like to thank all contributors and friends who made this release possible 🙏
If you read this far: yes, 🤖 were used extensively but at least this announcement is handwritten 🙂Since you mention bb, I just ran a quick test on my M4 Max:
$ let-go -e '(do (defn fib [n] (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))))) (time (fib 32)))'
Elapsed:
2178309
$ bb -e '(defn fib [n] (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))))) (time (fib 32))'
"Elapsed time: 293.669875 msecs"
2178309
Perhaps the brew build is behind?the VM is slower but the AOT output is faster
how do I "activate" that?
not sure if it matters, but 218 has been out for a while
(and hopefully this week 219). but congrats with the progress!
unfortunately, there is no easy way to run the new AOT pipeline yet, needs a small Go wrapper :|
that document doesn't tel me how to do AOT. Is this a command line flag?
you know what, I'll remove the bb claim
I have an easy way 🙂
gloat compiles binaries with lg using 3 different strategies
right, gloat can kick off the new AOT compiler, we don't have a command for this yet
I need to release the lg work. I'll do that tonight.
But I'll make comparison binaries now
@borkdude I removed the claim, you're right to question this - it's not easily repeatable without cloning the repo and running the benchmark script
$ gloat -Exxx
Unknown engine 'xxx'. Known engines: glojure (glj), let-go-lower (lgl), let-go-lower-vm (lglvm), let-go-vm (lgvm)$ gloat fib.clj -Elglvm -o fib-lglvm
Lowering to native Go with lg-compile...
Bundling bytecode with lg -c...
Building native binary with go...
Generated: fib-lglvm
$ ls -lh fib-lglvm
-rwxr-xr-x 1 ingy ingy 14M Jul 20 17:59 fib-lglvm*
$ time ./fib-lglvm
2178309
real 0m0.031s
user 0m0.029s
sys 0m0.003slglvm is let-go lowered w/ vm fallback
$ time bb fib.clj
2178309
real 0m0.432s
user 0m0.401s
sys 0m0.025s
for comparisonlowered == aot == generated go code
when it hits a form that isn't lowered, it trampolines to the lg vm. and all gains are basically lost
yeah we're working on this
fyi, I might have glojure aot faster than let-go 😎 stay tuned
I need a legetimate comparison with glojure. AI told me Glojure has better interop, but is reflective. Both seem to offer AOT now, but let-go AOT has less runtime overhead.
As a btw, don't know how other feel, but interrop with Go and full native comp (with cross-compilation) (ideally with low runtime overhead) are the only two things that "hosted on go" Clojure excite me for. An interpreter is only good to enable nRepl development at dev time.
I very much agree
Oh and also, nice work! I really appreciate all the efforts let's go !clojure-spin
There's a ton of stuff that the AOT isn't doing as efficiently as it should
Can confirm 😉
Clojure wasn't built in a day...
https://gist.github.com/ingydotnet/d935eee4a8cdfd6a28e05d3dc36c8529 is a comparison of bb, glj and lg (aot and vm) times. the glj and lg versions are not the latest though
Congratulations with the release! 🎉 And thanks for mentioning lgx and my other projects 🫶