Stream: ideas

Topic: Concurrent/threaded platforms


view this post on Zulip notramo (Sep 25 2026 at 15:34):

I would like to implement a platform in Zig, that calls Roc closures or entrypoints on different OS threads. Or if it's not possible, at least as stackful coroutines on the same OS thread.

https://github.com/roc-lang/roc/issues/11658
I would like to implement messaging between these fibers/threads: https://github.com/roc-lang/roc/issues/11634

Spawning a new fiber in Zig is probably not enough. What are the areas that cause risks? The reference counting?

How do the risks differ between a fiber concurrency solution and a parallel OS thread solution?

view this post on Zulip notramo (Sep 28 2026 at 17:27):

@Richard Feldman, could you point me in some direction? I don't need detailed guide, just some tips on where to get started, and what causes the main complexity.

view this post on Zulip Richard Feldman (Sep 28 2026 at 21:17):

reference counting should be fine, since we automatically do atomic refcounts on values that can potentially reach the host

view this post on Zulip Richard Feldman (Sep 28 2026 at 21:18):

so if the scope of what you're doing is just this, it should Just Work already:

I would like to implement a platform in Zig, that calls Roc closures or entrypoints on different OS threads.

view this post on Zulip Richard Feldman (Sep 28 2026 at 21:19):

in other words, you should be able to just call the compiled Roc functions from the host, pass those values around to other threads if desired, and everything should work (as long as you're maintaining accurate refcounting in the host and using atomic operations when necessary)

view this post on Zulip Richard Feldman (Sep 28 2026 at 21:21):

as far as pointing you in the right direction, this is an old implementation that used the original Roc (Rust-based) compiler, and an older version of Zig, but the host side should still work in principle: https://github.com/bhansconnect/roc-coro-webserver

view this post on Zulip Richard Feldman (Sep 28 2026 at 21:25):

some more detail on reference counting that might be helpful:

view this post on Zulip Richard Feldman (Sep 28 2026 at 21:25):

so that's what I mean regarding "you have to keep the reference counts accurate"

view this post on Zulip Richard Feldman (Sep 28 2026 at 21:26):

compiled Roc functions are, by design, totally stateless - that's one reason why the host has to provide things like alloc and dealloc

view this post on Zulip Richard Feldman (Sep 28 2026 at 21:26):

you just call them passing values, they operate on those values, call some functions the host itself provides (alloc, dealloc, crash, effectful functions, etc.), and then return, and that's it; there is no stateful runtime to initialize or deinitialize because once those functions return, they're done

view this post on Zulip Richard Feldman (Sep 28 2026 at 21:27):

if there's any leftover stuff to be cleaned up, it's all stuff the host already knows about (e.g. allocations done using the host's own allocation system)

view this post on Zulip Richard Feldman (Sep 28 2026 at 21:28):

but that does mean each compiled Roc function call is innately oblivious to what other Roc function calls are running, if any, and makes no attempt to coordinate between them - so the host is responsible for making sure they receive accurate refcounts when they're called, and then doing any necessary cleanup on the return values after they finish

view this post on Zulip notramo (Sep 28 2026 at 21:37):

Thank you for the info!

view this post on Zulip notramo (Sep 28 2026 at 21:38):

This seems simple with scalars. But what happens if I pass a list or a struct, that reference further values? Do i need to recursively increase the refcount on each one, or is it enough only on the outermost container?

view this post on Zulip notramo (Sep 28 2026 at 21:38):

As I understand from Zig platform glue, it would need recursive.

view this post on Zulip notramo (Sep 28 2026 at 21:41):

Also, I guess I would need to know the type of every passed value in advance, when writing the Zig code, so I can't rely on the type inference of the Roc type system to figure out what each Roc program passes to the platform. Given two Roc programs that would use the same platform package (but has nothing to do with each other), it's not possible that one program sends struct type A through send!() between its own fibers, the other program sends struct with type B. Because that would require host recompilation.

view this post on Zulip Aurélien Geron (Oct 08 2026 at 21:01):

FYI, I asked Astra to create a tiny platform named roc-parallel for parallel computing, for the purpose of an Exercism exercise (parallel-letter-frequency):

Here's an example:

app [main!] {
    pf: platform "https://github.com/ageron/roc-parallel/releases/download/0.3.0/ArsAKsVYCn93y2GdXRuMDN5DRrVyb8Fa8BJ3QtxqFxfF.tar.zst"
}

import pf.Parallel
import pf.Stderr

main! : List(Str) => Try({}, [Exit(I8), ParallelError([InvalidWorkerCount])])
main! = |_args| {
    result = Parallel.map!([1, 2, 3], { workers: 2, task: |n| n * 10 }) ? ParallelError
    Stderr.line!(Str.inspect(result))
    Ok({})
}

This will compute n * 10 for each item of the list [1,2,3] in parallel across 2 threads.

view this post on Zulip Luke Boswell (Oct 08 2026 at 21:04):

I'm really looking forward to all the innovation that will shake out in this area... I feel like there is so much potential for exploring new ideas and abstractions that give us nice developer experience and provide guarantees like performance etc

view this post on Zulip Luke Boswell (Oct 08 2026 at 21:05):

It's so much easier to throw something together now we have a more stable ABI and the tooling like roc glue to help.

view this post on Zulip Aurélien Geron (Oct 08 2026 at 22:08):

Yes, I barely run into any segfaults anymore, it feels so good! Quick question about Glue: is there any documentation about it? I'm kinda lost (a quick tutorial would be a great topic for the next meetup).

view this post on Zulip notramo (Oct 08 2026 at 23:44):

It's interesting, but my main reason for exploring this area is not performance. Often, the program logic requires multiple tasks to run at the same time, and I want a platform that can cover these use cases.

view this post on Zulip notramo (Oct 08 2026 at 23:45):

It's usually a simpler task to return a value when the parallel task finished running.

view this post on Zulip notramo (Oct 08 2026 at 23:45):

The main challenge is message passing while the task is running, so the value is reachable from two or more fibers/threads.

view this post on Zulip notramo (Oct 08 2026 at 23:46):

I guess this can mess up the GC.

view this post on Zulip notramo (Oct 08 2026 at 23:47):

Especially, when it's not a simple integer/string, but a nested data structure, with independently tracked items.


Last updated: Oct 15 2026 at 17:56 UTC