6 ms·
Show HN: I made a Clojure-like language in Go, boots in 7ms
Let-go is a Clojure-like language (~90% compatible with JVM Clojure) written in pure Go. It ships as a ~10MB static binary and cold boots in ~7ms - that's about 50x faster than JVM and 3x faster than Babashka. It has decent throughput on algorithmic workloads - within ballpark of the GraalVM-backed sci.
I started this project in 2021 as an elaborate practical joke: I wanted to have an excuse for writing Clojure while pretending to write Go.
Jokes aside, it turned out to be pretty decent: it feels like real Clojure, it has an nREPL server (supported in Calva, CIDER, etc.), it's easily embeddable in your Go programs (funcs, structs and channels cross the boundary without fuss). It's good for writing CLIs, web servers, data processing scripts and even doing some systems programming - I used it to write a deamonless container runtime. Oh, and it runs on Plan9.
Under the hood there is a fairly simple compiler and a stack VM, both handcrafted specifically for running Clojure-like code. The compiler can work in AOT mode producing portable bytecode blobs and standalone binaries (runtime+bytecode).
This is not a drop-in replacement for Clojure in general - it does not load JARs, it does not have all Java APIs and it most probably won't run your exiting Clojure projects without modifications. At least not at the moment.
Take it for a spin, tell me what you think. Issues and PRs are welcome!
- asdfasd323f 5mo ago[flagged]
- jeremyjh 5mo agoSo...you didn't ? https://github.com/nooga/let-go/tree/d9dc094822b2983ebf446048919f18da1beddb1d https://github.com/nooga/let-go/tree/d9dc094822b2983ebf44604... In 2023 he had a working Clojure compiler with: Macros with syntax quote, Reader conditionals, Destructuring, Multi-arity functions, Atoms, channels & go-blocks a'la core.async, Regular expressions (the Go flavor), Simple json, http and os namespaces, Many functions ported from clojure.core, REPL with syntax-highlighting and completions, Simple nREPL server that seems to work with BetterThanTomorrow/calva,
- deleted 5mo ago[deleted]
- dmitrygr 5mo agoYou should see how fast libc gets mmaped() into the VM and the first instr runs :)
- marcingas 5mo agoSure, I should clarify: The 7ms here is measured at the point where let-go starts executing user code. It takes 7ms to initialize the compiler, load all stdlib namespaces and compute all vars. So it's not "time to first instruction", it's "time to running your code".
- brazukadev 5mo agodo you know about Glojure? https://github.com/glojurelang/glojure https://github.com/glojurelang/glojure
- marcingas 5mo agoYes, I know about this one. I'm even comparing against it in my benchmarks :)
- rcarmo 5mo agoYou need to update the go-joker numbers, I removed the GIL yesterday or so and did some changes to the IR. ;)
- marcingas 5mo agoI think I've pulled the latest today but will double-check and update them again tomorrow. I'm still puzzled why it doesn't run the tak function. Btw. Have you tried running my benches? I'm very curious about your results!
- rcarmo 5mo agoI got tak fixed. There was an internal logic error, IIRC. A bunch of stuff got done.
- marcingas 5mo agoUpdated. Looks like my VM gets a beating from wazero but that's kind of expected :D
- ingy 5mo agohttps://github.com/gloathub/glojure https://github.com/gloathub/glojure is the actively maintained fork.
- bjconlan 5mo agoThis is the kind of clojure port that I always was looking for. Mostly because I thought go's core library and channels abstractions hits a simpler/nicer base API which would with the core & async apis (not to mention scratches my big beautiful binary itch) Thanks for your work will definitely check it out again once I get over renewed love for cpp (26) Edit how did glojure go under my radar also a great project from the looks
- marcingas 5mo agoThanks for kind words! Please don't forget to drop me an issue or two when you eventually get to it :)
- giancarlostoro 5mo agoI have played with the idea of making a “old school PHP” style DSL that takes advantage of the Go runtime and packages under the cover. I say old school PHP because PHP used to be a web focused DSL its no longer the case, I feel like it would make for an interesting easy to use backend language similar to PHP but with the full power of Go behind it. Clojure is an excellent choice.
- ingy 5mo agoTry out this Wasm browser REPL https://gloathub.org/repl/ https://gloathub.org/repl/ Gloat is a Glojure AOT automation tool. I worked with James Hamlin to get Glojure AOT going last summer and have been moving it forward since. I've also been working with marcingas (nooga) to get Gloat/Glojure/let-go all cooperating.
- deleted 5mo ago[deleted]
- asdfasd323f 5mo ago[flagged]
- marcingas 5mo agoYes, I have used AI to boost Clojure compat and fill out some blanks but the runtime itself is not vibecoded. I wrote it myself between Jan 2021 and July 2023. All commits on GH.
- blanched 5mo agoYou made an account just to post this low effort “criticism”? What’s the point?
- adi_kurian 5mo agoIs it bad? Did you try it?
- jeremyjh 5mo agoDid you even look at the repo history? Clearly it blasted off this year that way but that isn't how it started. Probably he got way more into it once he could make faster progress on all the yak shaving required to make it more useful.
- marcingas 5mo agoYeah, pretty much. I abandoned it in 2023 due to lack of time. At this point it had enough lift for solving AoC problems and writing small scripts. I've recently dusted it off and did the boring parts of the "roadmap" with Claude.
- bpicolo 5mo agoAs much as we may all hate to admit it, vibecoding is very close to just being the new programming.
- chr15m 5mo agoPR most welcome for https://github.com/chr15m/awesome-clojure-likes https://github.com/chr15m/awesome-clojure-likes
- marcingas 5mo agoAdded https://github.com/chr15m/awesome-clojure-likes/pull/27 https://github.com/chr15m/awesome-clojure-likes/pull/27 Thanks for letting me know :)
- asdfasd323f 5mo ago[flagged]
- deleted 5mo ago[deleted]
- asdfasd323f 5mo agoThe readme clearly has abundant emdashes and emojis everywhere, the code itself is obviously vibed. Not really sure what you're objecting to, to be honest.
- marcingas 5mo agoYeah, it has em dashes alright. But the emojis you're referring to were committed in January 2023 (0c4925c). But that's besides the point I guess. What is your point?
- j3s 5mo agoabsolutely sick of reading through obviously AI-slopped READMEs. it's your project, take a little pride and tell me why i should like it quickly instead of asking your agent to rattle off a list of features -- it's severely boring & offputting.
- marcingas 5mo agoThanks for feedback. Here's a pre-AI-slopped README https://github.com/nooga/let-go/blob/98c2e2ebf38519bceb4f7991529f03b0125a4909/README.md https://github.com/nooga/let-go/blob/98c2e2ebf38519bceb4f799... You can also refer to the HN post itself - it says why I think it's cool.
- j3s 5mo agoapologies if i was blunt - readme sloppage is a particular annoyance of mine that is quickly becoming common. i'm not against vibecoding, far from it. but a readme is a part of a project that humans immediately touch - seeing it littered with em-dashes signals carelessness. i appreciate you taking my feedback with grace.
- marcingas 5mo agoNo worries at all. I understand your point. I'll look into fixing this!
- rcarmo 5mo agoI would like to point out, again, that em dashes are very much used by humans that run macOS or iOS — like in this case.
- isityettime 5mo agoAlso Linux, where it's easy to configure a compose key to mnemonically type all the Unicode goodies you can think of. Android's software keyboards generally make it easy, too.
- 5mo ago
- faangguyindia 5mo agoI am finding i need "Rails" but i like single binary deployment of Go and fast/low resource usage like Go. Is it possible for now?
- marcingas 5mo agoI think you could make a framework on top of this. It doesn't yet run unmodified Clojure libs like hiccup but it wouldn't be hard to roll something relatively simple and solid in let-go. IMO
- veqq 5mo agoNice! I recently played around with a Lisp syntax for Go semantics: https://codeberg.org/veqq/Joe https://codeberg.org/veqq/Joe As far as JVM-free Clojure-like, Janet is really nice. I've been using it in production for a while: https://janet-lang.org/ https://janet-lang.org/ There's also Fennel if you want the Lua vm and libraries.
- marcingas 5mo agoThanks! Joe looks good! As for Janet - never tried it myself but I always thought it's doing its own thing instead of trying to be Clojure.
- TJSomething 5mo agoWhile Janet pulls from a few inspirations, the syntax is pure Clojure. I always figured that it was trying fix up the bumpy parts in Fennel to enable a programming style that was more consistently Clojure-like and functional than could be done in Fennel, since Fennel ultimately has to use Lua's semantics because Fennel compiles to Lua.
- veqq 5mo agoIt's a bit harder as Fennel can produce pure functions, whereas basically everything in Janet's standard library outputs mutable structures etc. Janet style tends towards (elegant) imperative programming.
- deleted 5mo ago[deleted]
- fuzztester 5mo agoFor what types of work do you Janet in production?
- veqq 5mo agoI manage some client websites made with https://github.com/joy-framework/joy https://github.com/joy-framework/joy for example https://codeberg.org/veqq/janetdocs/ https://codeberg.org/veqq/janetdocs/ Some email stuff I don't know how to summarize well Some data processing/aggregation servers Some accounting stuff I'm trying to build a declarative DSL https://lobste.rs/s/ylq7sd/what_are_you_doing_this_weekend#c_wjvizz https://lobste.rs/s/ylq7sd/what_are_you_doing_this_weekend#c... which I could port production Common Lisp/Prolog stuff to, but I probably won't for performance reasons.
- boguscoder 5mo agoMicro nit: it says 7ms cold start and then 6ms just few lines lower.. maybe it gets faster as you read README
- marcingas 5mo agoFixed, thanks! It's 6-7ms on my machine. Median seems to be around 6.5ms :)
- deleted 5mo ago[deleted]
- lsh0 5mo agoAn alternative is Joker: https://joker-lang.org https://joker-lang.org I think it is brilliant and completely underappreciated :)
- marcingas 5mo agoWhat I appreciate about Joker is how smoothly it wraps Go libs. It seems that they have covered everything that Go has to offer. I'm trying to avoid adding too much though, I like that let-go fits in 10MB :)
- lenkite 5mo agoI wish this had a better language name than just "lets-go". How about "clogo" ?
- marcingas 5mo agoNaming is hard but I like let-go, it's a layered pun :) (let [...] (go ...)) It lets you let in Go! Clogo is a no-go for me. Maybe you have some other ideas? I'll consider good ones :)
- dxdm 5mo agoFWIW I like let-go a lot as the name. I'm relieved that clogo is not an option for you. It has some strong, malodorous campground toilet connotations to my foreign-language-trained ears. Loogo? Pottygo? Go number 2? Yikes to all of those. And now, as bonus content, for something completely different: https://youtu.be/M3-51DhOzHE https://youtu.be/M3-51DhOzHE?
- marcingas 5mo agoI laughed, audibly :D
- lenkite 5mo agoGojure is simplest. Just a bit close to Glojure which is already taken. Goclo, Gophoj,Gorjure ..ok my tongue is paining now verbally trying out combos.
- achenet 5mo agoThis is beautiful, makes me wish I'd made it. Excellent work, thank you for sharing it with us ^_^
- marcingas 5mo agoThank you! If you ever want to contribute PRs and issues are warmly welcomed :)
- phplovesong 5mo agoThere seems to be a surge in compile to Go projects recently. To me this signals that the runtime / stdlib of Go is one of the best out there (when going the GD'd route), but the surface level (syntax) is too simple/verbose and lacks the expressiveness developers want. So far Lisette (http://lisette.run http://lisette.run) seems to be the best/most active version of a compile to Go language out there.
- christophilus 5mo agoThat does look pretty good. I don’t love the mixing of PascalCase / camelCase and snake_case, though.
- phplovesong 5mo agoThats just a pragmatic design decision for Go interop, as Go went nuts with public being UpperCase. Theres no camelCase tho? Snake case and PascalCase fir Go modules interrop.
- networked 5mo agoI'll be happy is Lisette succeeds, but I like Soppo (https://github.com/halcyonnouveau/soppo https://github.com/halcyonnouveau/soppo) for staying closer to Go and not introducing this mismatch.
- NetMageSCW 5mo ago“let data = io.ReadAll(file)?” That’s Pascal case any way. Looks sort of camel case with the “io” being lower case.
- phplovesong 5mo agoYes. PascalCase for Go, snake_case for Lisette. I find it quite good actually as i can see what hooks into the Go ecosystem instantly. Ofc you can write your own wrapper, but so far i have not bothered.
- asdfasd323f 5mo ago[flagged]
- asdfasd323f 5mo ago[flagged]
- immanuwell 5mo agojvm clojure's startup tax is exactly why it never cracked the serverless/cli niche, and this pure-go implementation is the kind of unhinged side project, good luck
- marcingas 5mo agoThanks! I've been looking into custom runtimes for AWS Lambda and I think it's not going to be hard to have let-go lambdas. Even though the language is not 100% compatible it should be enough for request handlers and data processing. Throughput isn't on par with JITed impls but it's not bad enough to be impractical IMO
- cutler 5mo agoJoker, Janet, Glojure and now Let-go. Am I missing something?
- edem 5mo agoThe JVM can boot up in microseconds you just have to tune it a bit.
- marcingas 5mo agoThe JVM itself - yes, but then you need to wait for Clojure itself. Clojure is famously slow because it interns a bunch of stuff and computes var references every time it boots. I never intended for let-go to be a race car but small distro, low memory usage and snappy start are its priorities at the moment.
- ever_same_4 5mo ago[dead]
- asdasd44123123 5mo ago[flagged]
- asdasd44123123 5mo ago[flagged]
- asdasd44123123 5mo ago[flagged]
- slantedview 5mo agoVery cool project!
- ever_same_4 5mo ago[dead]
- jeremyjh 5mo agoHow do you explain how more than half of that work was done in 2021? Or did you not look at the repo either? Even in 2023 AI could not really vibe code much of anything. Tell me about the AI coding tools available in 2021 though. It was all done with autocomplete? created: 7 hours ago I’m sure you have some impressive work from that era to share here as well.
- hope2 5mo ago[dead]
- ever_same_4 5mo ago[flagged]
- didibus 5mo agoCool, I think at this point, since there's a few Clojure Go dialect, what I'd like to understand most is which one is fully hosted on Go, has as good interop as JVM Clojure has with Java, where I can both use what I make from Go, and also use Go from Clojure, and even create mixed projects would be nice. And also, truly details the differences, beyond interrop, what is not the same and differs.
- marcingas 5mo agoI think Gloat/Glojure has the best hosted runtime story because of its AOT to Go src pipeline - you can grab anything Go at compile time. OTOH let-go can roundtrip any Go value including structs, functions and channels but it does not allow pulling arbitrary go libs without wrapping them up first - they'd need to be built into the runtime for this.
- dharmatech 5mo agoAmazing that it can run in plan9! It would be awesome if go was a first class language on 9front. I.e. ships with it. I've been messing around with a social network for plan9: https://youtube.com/watch?v=q6qVnlCjcAI&si=MBCeM0QdA0WsKAe7 https://youtube.com/watch?v=q6qVnlCjcAI&si=MBCeM0QdA0WsKAe7 It's all in rc and awk. There are places where go (or clojure!) would have been nice.
- marcingas 5mo agoI started publishing amd64 and arm (32) binaries for Plan 9 in GH releases. I tested the amd64 one on 9front and everything seems to work. The CLI is not very Plan9-y but I'm happy to make the port more native at some point :)
- dharmatech 5mo agoAh, awesome! I'll head over to the releases.
- marcingas 5mo agoLove the demo for 9social! I'm not a user myself but I'm always inspired by the Plan 9 ways :)
- dharmatech 5mo agoThanks for checking it out!
- sagar6164 5mo ago[dead]
- fizza_pizza 5mo agoThis is really cool. “I wanted an excuse for writing Clojure while pretending to write Go” genuinely made me laugh. The 7ms startup time and Plan9 support are both kind of wild too.
- marcingas 5mo agoThanks! Happy that you've noticed :)
- geokon 5mo agoIt's interesting how many projects seem to be in large part trying to address Clojure's slow startup time. Esp since Project Leyden seems to be around the corner and seems like it will solve the underlying JVM issue once and for all (making all these projects a bit redundant). Though maybe I'm missing something :)