So, I wanted to try out Fable and thought a fun test would be a project I actually want to exist already: basic-webserver on the new Zig compiler. :sweat_smile:
Full disclosure: I know nothing about low-level programming – the AI did the heavy lifting and I steered (kind of), kind of like @nandi did a couple of weeks ago. So, please, forgive me!
I genuinely can't tell whether the result is useful or just well-organised slop. What I can tell is that it builds and the examples work, on macOS (ARM), against compiler commit 48b28c07:
![]()
![]()
Check out the README for detailed info: https://github.com/studiorubenz/roc-experimental-basic-webserver-zig
It's also worth noting that, unlike the official ports, the host is written in Zig, not Rust.
I'll happily throw all of this away the day the official one lands; the ABI notes in the repo (IO-PORT-PLAN.md) might outlive the code.
Feedback very welcome – I'm especially interested in whether the Roc in the examples is idiomatic, or unidiomatic slop :grinning_face_with_smiling_eyes:.
Pretty cool Johannes, I did notice it tossed out a whole lot of tests and examples :p
Claude does this style often:
seed_64 = match Random.seed_u64!({}) {
Ok(n) => n.to_str()
Err(RandomErr(_)) => "(random error)"
}
Using ? is a lot nicer.
Same here:
path = "/tmp/roc-webserver-system-probe.txt"
match File.write_utf8!(path, "round trip äöü") {
Err(FileErr(_)) => "write_utf8 FAILED"
Ok({}) =>
match File.read_bytes!(path) {
Err(FileErr(_)) => "read_bytes FAILED"
Ok(bytes) =>
match File.write_bytes!(path, bytes.concat(" + bytes".to_utf8())) {
Err(FileErr(_)) => "write_bytes FAILED"
Ok({}) =>
match F
Thank you for your feedback on the AI-generated code, @Anton ! It's not something I take for granted, and I really appreciate it. I'll try to learn as much as I can from it. :slight_smile:
The mutex is a bit strange as well... not sure if that is necessary.
This file demonstrates ? nicely: https://github.com/roc-lang/basic-cli/blob/migrate-zig-compiler-edits/examples/command.roc
I also notice some differences in host.zig compared to Luke's platform like in rocReallocFn: https://github.com/lukewilliamboswell/roc-platform-template-zig/tree/5225da1582a17fcc36c9d00062adfc6659796bf2
I do like that open source gives people the possibility to take matters in their own hands :)
Porting basic-webserver properly is still a hard task for the best AI, but I imagine this could work perfectly satisfactorily in other scenarios. I hope it leads more companies to open source their app software so frustrated consumers can fix things :p
It's nice to know I can still do things fable can't :smile:
@Johannes Rubenz this is really cool. Id love to know how you got the platform started.. did you point Claude at an existing platform like my zig template or maybe the tests in roc repo, or use roc glue.
hey @Luke Boswell , I naively pointed Fable at the old rust compiler version and asked it to rewrite it for the new one in zig. Only after @Anton's kind feedback did I point it at your zig-platform-template and let it incorporate the ? error handling etc.
Zig and Rust are unfortunately out of my league... But what do you think of the machine-generated Roc code? I tried to enforce the new syntax and idiomatic style as much as possible... :sweat_smile:
imports the compiler's own builtins module directly
You should checkout the roc glue subcommand... it generates the interface and some nice idiomatic bindings for you (in C, Rust, or Zig)
@Luke Boswell :eyes: https://github.com/studiorubenz/roc-experimental-basic-webserver-zig#regenerating-glue
The app - host ABI is about to change dramatically so switching to glue will make the transition much easier. :grinning:
case in point: https://github.com/studiorubenz/roc-experimental-basic-webserver-zig/commits/main/ :slight_smile:
It's working for you? cool.
I'm just upgrading my template platforms now, hopefully I can cut a release
Ecosystem-wise, is Zig a better choice than Rust? I understand the compiler re-write, but I personally think that Rust is a better fit for host platforms, due to the ecosystem-size but there might be some advantages I don't know of.
Cool experiment in any case!
I think it's probably too early to fully understand the trade-offs between the two.
We haven't seen many production Roc platforms in the wild, Zig is also early-mid development as a language itself -- and most significantly our ABI or linking strategy between the app and platform host has been evolving as recently as yesterday.
What I have really liked about Zig is the tooling and control over low-level things. Authoring a platform (until recently with glue) has required pretty unique control over things like the symbols that end up in the pre-built host static library etc.
So I wouldn't be surprised if you were aiming to build a platform for industrial controllers you might choose Zig (or C), and if you were building an enterprise service with Roc scripting capabilities coordinating various effects you might choose Rust.
Not sure that helps at all?
Isn't it possible to code a platform in any language you prefer, as long as it respects the C ABI? So the choice of language for the compiler doesn't affect the language used for the platform. I may be totally wrong, but that's what I thought.
Yeah I wont be surprised to see Kotlin, Swift, Go platforms popping up soon
When we still had the old compiler we did sometimes have problems getting Rust to do the specific linking we wanted but that may no longer be a problem.
But what do you think of the machine-generated Roc code? I tried to enforce the new syntax and idiomatic style as much as possible...
Nice improvements @Johannes Rubenz :)
Stdout.line!("ws: ${frame.message}")
You may want to use dbg here, those calls will get filtered out for optimized builds (or they will be very soon). Stdout printing can delay things a lot if you start doing benchmarks.
amp = replace_all(input, "&", "&")
lt = replace_all(amp, "<", "<")
gt = replace_all(lt, ">", ">")
quot = replace_all(gt, "\"", """
You can chain these together with static dispatch for a cleaner look without intermediary variables. That also reduces the probability mistakes if you add lines later.
chat_page : Str
chat_page =
\\<html lang="en">
\\<head>
You may find it nicer to put this in a separate html file and use import as Str.
Wow, thanks @Anton for the feedback, which I've already incorporated and pushed upstream :check: ! I can actually use a lot of it for my Roc study plan as well, which is my primary goal at the moment.
(The plan spans 98 days (appropriately called "98 Days of Roc :rock:" :joy:) and is based on an AI-generated tutorial with 28 chapters. On top of that, I've built a validation pipeline that automatically checks every code example from the tutorial against the compiler, yolo! Now it's up to me to verify everything as I work through the tutorial and manually fix anything that sounds strange or seems wrong.)
That's also why I tried to get not only the basic web server working, but also basic CLI. And I "taught" my REPL to return type annotations. :laughing:
I'm having so much fun with all of this, and you, @Luke Boswell and the rest of the community are so supportive and motivating — thank you! :heart:
Anton said:
You may want to use
dbghere, those calls will get filtered out for optimized builds (or they will be very soon)
more specifically, "very soon" will be once this PR lands :smile:
Last updated: Jun 16 2026 at 16:19 UTC