(copy and paste from Opus 5.5; collaboratively-executed)
On average we're about 5.5x slower than native Roc. That's the geometric mean of the five work benchmarks
the reveal: I have a LuaJIT backend, lowered from LIR, working for Roc, that passes the entire test suite except for 1 failure that the native Roc also currently fails on; it is far faster than Python, Ruby, etc. as a "scripting language" not requiring compilation, while letting you enjoy all of the Roc niceties. :grinning:
I also have a few bugfixes for Roc proper to PR, just need to get my github signing ability back (long story)
Why this heresy: I liked LuaJIT (speed, simplicity) but not better than Roc; I also already have luajit installed everywhere, and wanted access to Roc without (yet) installing the whole chain everywhere.
Thoughts?
This reminds me of a segment from Richard Feldman's podcast Software Unscripted where he and Louis Pilfold discuss how Gleam came to having Javascript as a compile target.
I'm not knowledgeable on how much it affected the core mission of Gleam. So, I wonder how much a LuaJIT backend would affect Roc?
as a "scripting language" not requiring compilation, while letting you enjoy all of the Roc niceties.
AFAIK, the goal for Roc is to have sub-second compilation time for debug builds. Basically usable as a scripting language, even in AOT mode.
I like that! And I already built some tooling that basically caches a compiled version of an executable script (while allowing you to continue to run the script directly, but it does an "exec" underneath)
Ah, forgot to mention that it has some rudimentary interop as well (running luajit code from the roc side and receiving typed values back, running roc code from the luajit side with the same types of side-effects)
Since LuaJIT is trivially-embeddable everywhere, this also now means Roc is trivially-embeddable everywhere
I'd like to know if WASM (which is quite fast) might end up the interoperation lingua-franca at the lowest layers
What is the advantage of this over a native binary?
It's deployable everywhere, and you wouldn't even need LuaJIT installed.
I routinely use 3 OS'es on any given day. ;)
And 2 chip archs. ;)
I have a NixOS machine for pure dev, a Mac for secondary dev and "life apps", and a Windows box for gaming, testing my Windows ports and NixOS-on-WSL
About a year ago I decided to just stick LuaJIT everywhere and replace any Bash scripting that was more than 15 lines or so with Lua. Everything instantly became more maintainable, more portable and much faster.
I'd love a portable Roc solution that didn't require me to rebuild it everywhere. But also, Luajit really is kind of everywhere. Finance software to games. Cheap embed with C FFI. Roc being able to ride on that without much reconfiguration might be a foot in the door where it might not otherwise be.
(At the cost of being 5-10x slower. But logically correct.)
This would add lot of complexity to the Roc compiler, at the benefit of removing a few lines of shell code for deployment.
Roc can cross-compile from any host to any other arch and OS combination. This means that you can build your scripts on one machine for all of your devices.
How do you deploy your scripts?
It already works. There's no added complexity. It's lowered from LIR, which is generated by the compiler, and spits out a .roc.lua if you just specify the build option. But I need to play with it more. Maybe there's a complexity I'm missing.
I sync scripts through git, usually with Nix controlling deps.
And truth be told, it's not legit unless it's battle-tested in prod, and this hasn't been.
How is LuaJIT better than WASI? Is it lighter?
It's lowered from LIR, which is generated by the compiler, and spits out a .roc.lua if you just specify the build option.
So it's a separate tool, with no modifications required to the Roc compiler?
How is LuaJIT better than WASI
Good question. Well for one thing it's battle-tested and already installed in way more places, many of which would surprise you (it did me). LuaJIT has trivial C FFI access, for one thing. It's also more legible to humans than WASI (if you deal with it via WAT). And honestly, part of me was thinking "what's the best first language to teach my son?" and both Roc and Lua were at the top of that list for fairly different, but both legitimate, reasons. ;) ("Learning a language" may be a thing of the past, soon?) But honestly, yeah, WASM is coming in hot here, and I honestly think it's going to sort of be the next LLVM in terms of "popular intermediate build target."
AI writes LuaJIT well, but (funny thing) it argued against me having it write Lua and actually said Roc was better, especially when considering agent/human collab (this is the current belief over here, btw, about where things are going). Of course, it said this after the project was already working. LOL.
It cited Roc's immaturity as a strong argument against it, though. (But that's just time and effort to surmount.)
It's mostly an experiment. Giving Roc access to LuaJIT code also gives it the same trivial C FFI access Luajit has, which might make it easier to integrate with some things.
"Learning a language" may be a thing of the past, soon?
Definitely not. It's fun. Probably even more new languages will be created, with LLM help in the compiler development.
Agreed. It is always going to be fun to some. Which is good, because there's a distinct possibility that no matter how smart AI gets, it may simply create more-difficult-to-run-down bugs, and then we need the programmer-humans again!
And also agree on even more languages... and language forks. The cost of code creativity (CCC?) has gone way down.
This being a perfect example. This experiment took about a day (as in, Opus 5.5 with my oversight literally took about 24 hours to complete it.)
I know a guy who was able to use Clojure in a Java shop (salesforce, sigh) only because Clojure was a JVM language.
If someone somewhere had already accepted Lua into their setup, now someone can perhaps shoehorn Roc in. ;)
(nonsequitur)
Another thing that might be fun to do is putting a Roc backplane on my Aedicule sideproject
https://github.com/pmarreck/aedicule
The idea behind Aedicule is "universal GUI frontplane" providing drawing/sound/sprite/input primitives, and controls via gpui_component. It's built in Rust and uses GPUI from the Zeditor project. The backplane can be built in anything. Currently it only supports WAT (webassembly/webassembly text) but it's pluggable. I could probably easily add Roc, assuming its wasm output works, and then you'd get the same code running identically as a performant GUI in an app across 3 OS'es as well as web browsers (which is what the handful of existing demos at https://pmarreck.github.io/aedicule/ all already accomplish).
https://github.com/pmarreck/roc_luajit (forgot to put the repo URL out there, whoops)
After re-watching the segment I linked earlier, reading the FAQ, and giving it some thought I am hesitant to be in favour of adding a Lua backend.
I don't think the risk of adding Lua as a compile target is negligible. For one it is a large amount of code to maintain.
More importantly, it might lead to a situation where implementing certain features or optimizations becomes more difficult because it doesn't mesh well with the Lua backend.
This is outlined in the Roc FAQ. https://www.roc-lang.org/faq#other-compilation-targets.
So it may push Roc toward features which it may later come to regret. Please see this, https://youtu.be/WC_j91qogyY?t=2561, segment about Gleam as an example of that.
There's also the question of which version of Lua to support. My understanding is that there are several incompatible dialects, each with their own semantics, features, and bytecode format. http://lua-users.org/wiki/LuaVersionCompatibility
Lastly, Roc already has a great story regarding C FFI and as an embedded scripting language through platforms. https://www.roc-lang.org/docs/main/langref/platforms/#domain-specific-functionality
Could Lua be integrated into a platform so that a host that embeds Lua use that through it's C FFI?
@Peter Marreck you're not proposing to upstream this right? I didn't get that impression from your post.
I agree, this looks pretty close to a heresy :cross: -- but it's also super cool to see. I think it demonstrates how easy it can be for people to pick up Roc and use it in various places pretty easily to meet their unique needs.
We were talking the other day in Zulip about using Roc as a library somewhere, and I suggested you can point at the repo and use the models for the core compiler pipeline. This is a demonstration of exactly that already in the wild.
I dont think the core project has any intention of supporting a LuaJIT backend, but if someone wanted to have a downstream project then it's pretty easy to set up and maintain - I imagine the LIR boundary is a nice place to cut from.
I'm curious how you went with the platform side of things? the platform/app abstraction is pretty ingrained in everything and I could imagine that might have been interesting to handle.
Also at the risk of heresy -- here is a PR deleting most of the code in your repo :wink:
https://github.com/pmarreck/roc_luajit/pull/1
I wanted to confirm for myself that it was possible to use Roc the way I had been talking about. It has been 6 months or more since I tested it and sure enough there had been drift which blocks it. I've made a PR for roc that fixes that and pinned the roc git sha for you here.
This means you can use Roc's zig modules like any other zig library which is much easier to manage I think .
Last updated: Oct 15 2026 at 17:56 UTC