I'm confused about what a platform needs to include. The basic-cli seems to include implementations for all of the builtins. But other demo platforms are much smaller. Are the builtins in basic-cli just there for convenience with interfacing between Roc and Zig? If so, where are the real implementations of the builtins?
When you say builtins, are you referring to List
and Dict
and all, or stuff like File
and Http
?
Roc's "builtins" are those types defined here: https://github.com/roc-lang/roc/tree/main/crates/compiler/builtins/roc
And the basic-cli interaction with them is auto-generated as "roc glue"
The other types like File
and Http
are defined in basic-cli specifically for now because it's easier to maintain them there, but will probably get pulled into separate packages at some point
Sam Mohr said:
When you say builtins, are you referring to
List
andDict
and all, or stuff likeFile
andHttp
?
List, Dict. Str...
Thank you!
In particular, the builtins like List
and Result
are included by the compiler without import in every Roc program
Which is why you never see them explicitly imported
Follow up: how would one add support for a new platform language to roc glue
?
[edit] I found it at https://github.com/roc-lang/roc/tree/main/crates/glue
yep!
I think @Sven van Caem was working on the glue recently, maybe he can help you figure out how to get started?
Thanks! I'm interested in (perhaps) making a better Go platform than https://github.com/roc-lang/examples/tree/main/examples/GoPlatform, so might give it a try to add support for Go to glue.
btw. I noticed GoPlatform is missing roc_panic, roc_memset, roc_getppid, roc_shm_open, and roc_mmap. Are those optional?
I'm not sure.
Does it run? haha
Also, having Go glue could be helpful for our attempt to make stackful coroutines work, so this would be a useful endeavour!
It runs the provided example, but I don't know what might break if I try to use it.
Sam Mohr said:
I think Sven van Caem was working on the glue recently, maybe he can help you figure out how to get started?
I might be able to answer questions! I'll have more time later though
Sven van Caem said:
Sam Mohr said:
I think Sven van Caem was working on the glue recently, maybe he can help you figure out how to get started?
I might be able to answer questions! I'll have more time later though
No rush! I'm pleasantly surprised to have gotten any answer at all so quickly. :-)
Matt Harden said:
btw. I noticed GoPlatform is missing roc_panic, roc_memset, roc_getppid, roc_shm_open, and roc_mmap. Are those optional?
It seems to depend on the language e.g. a C app will run just fine without them as long as they're not used, but a Zig app won't compile without them
Context on stackful coroutines, btw: https://roc.zulipchat.com/#narrow/channel/304641-ideas/topic/stackful.20coroutines.20in.20hosts/near/473001620
https://github.com/lukewilliamboswell/roc-platform-template-go
This may be of interest.
Also checkout some of @Oskar Hahn work on different go platforms.
Luke Boswell said:
https://github.com/lukewilliamboswell/roc-platform-template-go
This may be of interest.
Also checkout some of Oskar Hahn work on different go platforms.
Oh! thank you, I missed those.
Matt Harden said:
btw. I noticed GoPlatform is missing roc_panic, roc_memset, roc_getppid, roc_shm_open, and roc_mmap. Are those optional?
roc_panic is called by roc when there is a crash or a runtime error. It is needed.
The others are part of the shared memory infra that is used for roc test and expect
. I believe the plan is to remove those. I made a start on a PR in that direction...
https://github.com/roc-lang/roc/pull/7256
So RocStr
and RocList
in https://github.com/lukewilliamboswell/roc-platform-template-go/blob/main/host/roc/roc_std.go are hand spun, right?
Yep
So the host
directory is for the Roc to host language basic interface, and the platform
directory is for the extended capabilities provided to Roc by the platform?
A roc app doesn't exist without a platform. The platform includes a host which is written in another language like Go, and is the executable that starts first and then calls into roc.
The platform files are all .roc and are basically just an API or interface between the roc part and the host part.
Luke Boswell said:
The platform files are all .roc and are basically just an API or interface between the roc part and the host part.
I see now; thanks.
One day we might have a Go package for RocStr and RocList and the builtins so platform authors dont have to worry about the internals of how roc handles things. But for now we have been writing them by hand.
We would want to generate those with roc glue, right?
I dont think so. Glue is more for generating types defined in the platform, like if you make a record or tag union you would use glue to generate interfacing code in go. It would probably use the Go package that already had impls for RocStr and RocList etc.
So the builtins should live in a Go package/library somwhere. e.g. RocResult
, RocList
And custom types specific to the platform are generated by glue. E.g. HttpResponse
, File
Which builtin Roc types would we want to have hand implementations of in other languages? It seems like that could be a maintenance issue. Str and List are fairly complex already and the more different implementations we have the harder they will be to change without breaking things.
It seems like a world where glue creates a working but perhaps suboptimal impl of those types for you would be nice, as long as you keep the option of replacing them with better implementations manually.
glue/README.md agrees with what you're saying though.
I noticed that build.roc
in https://github.com/lukewilliamboswell/roc-platform-template-go tells the go
command to use zig cc
, meaning there's a dependency on Zig. Is that necessary?
I really think for these types we should enable roc to expose a c abi interface for the platforms to use
Then the platform can just see them as an opaque bag of bytes
I came to this realization after making Dict. It is too complex to be worth implementing in platforms, yet it would still be very convenient to have in platforms.
That said, monomorphization makes this all a tad tricky.
we should be able to expose zig versions that take size and alignment as arguments to all their operations, which the host needs anyway - and I think that basically takes care of monomorphization except for refcounting, yeah?
Yeah. Something along those lines (but doesn't work for dict which is written in roc)
Brendan Hansknecht said:
I really think for these types we should enable roc to expose a c abi interface for the platforms to use
Can you give me a simple example?
Like List.len
maybe?
It'd be great to explore this direction further... particularly if it greatly simplifies the glue stuff Sven is working on
Or at least simplifies the roc_std for zig/rust/go we've been talking about
It would be very similar to the zig builtins for roc list, but exposed as c abi. Then each language is ready of implementing roc list would just wrap our single bespoke c abi implementation
Really might be best to clean up the zig builtins and use that as the base. Though might be better to avoid the zig dependency and make this all in C.
Also, this still isn't enough cause our zig builtins don't understand refcounting. This is part of the reason I think it would be better for roc to generate these functions for each platform.
Is there an opportunity to kill two birds, with the zig package we want to make?
Imagine that instead of exposing init and respond from basic webserver, it also exposed a whole suite of functions related to each of the primitives used in init and update.
Oh interesting... you're imagining roc exposes more functions that are related for the primitive types exposed to the host. Nice
Like in the roc-on-simple example..
Smf : {
header : Header,
tracks : List Track,
}
mainForHost! : {} => Smf
Here we might include a void roc__smf_refcount_inc()
or something?
Exactly. Plus the primitives to interactive with a list of Track
(including refcounting a Track).
This stuff is hard to build out in glue, but roc already knows how to do it
So it would be nice if roc could expose it to the platform
Then glue truly is just glue code and not implementation code
This is where I think we need to head
yeah we should spec this out!
definitely seems like the right approach based on what we've learned :big_smile:
I think keeping the implementation in Zig should be fine - either way, the host just needs some extern definition, which can be hardcoded .h and .rs files that we can write tests against using zig alone, and which glue can just copy/paste into the output dir
Coming back to go glue code. I also tried it some time ago. My problem was, that cgo needs a .h file, with all types. This .h file needs also the signatures of the provided functions, like this one: https://github.com/lukewilliamboswell/roc-platform-template-go/blob/0e8d53b6087662ea231a164a059f1c2ba0a91c34/host/roc/app.h#L14
But this is currently impossible with glue, since the signature of the exported functions are not provided by the glue API.
The separate .h file is also the reason, why I don't think a roc-std-go package is possible. Your app.h file could not import/include the std.h file, provided by the package. So your app.h file could not use types like RocStr. Therefore I think the std types have to be generated for each app with glue.
I don't know if this would change, if roc would provide the types by API. I think it would still be necessary to generate the type definition and all std function definition with glue to use them inside the app.h.
Brendan Hansknecht said:
Imagine that instead of exposing init and respond from basic webserver, it also exposed a whole suite of functions related to each of the primitives used in init and update.
Love this idea! Would really lighten the load for a glue spec author.
Oskar Hahn said:
Coming back to go glue code. I also tried it some time ago. My problem was, that cgo needs a .h file, with all types. This .h file needs also the signatures of the provided functions, like this one: https://github.com/lukewilliamboswell/roc-platform-template-go/blob/0e8d53b6087662ea231a164a059f1c2ba0a91c34/host/roc/app.h#L14
But this is currently impossible with glue, since the signature of the exported functions are not provided by the glue API.
The separate .h file is also the reason, why I don't think a roc-std-go package is possible. Your app.h file could not import/include the std.h file, provided by the package. So your app.h file could not use types like RocStr. Therefore I think the std types have to be generated for each app with glue.
I don't know if this would change, if roc would provide the types by API. I think it would still be necessary to generate the type definition and all std function definition with glue to use them inside the app.h.
If all Roc values were passed around as opaque pointers in the API you wouldn't need any types in the .h files.
well it's pretty common that the host wants to do things with the values it gets from Roc, e.g. read the contents of a string or list
so in those cases it needs something more than opaque pointers
Richard Feldman said:
I think keeping the implementation in Zig should be fine
I don't think so. Zig does not know how to recount things. Only roc does. It depends on roc passing it functions that tell it how to recount things. I think we need to leave this all to roc. Otherwise, glue becomes way harder.
Roc will surely already be generating these functions anyway, it needs them to do refcounting of things passed into roc.
I guess after recounting, the rest could be in zig theoretically.
This is where you get a trade from:
Extreme 1, like today, platform has to implement everything, super brittle
To:
Extreme n, platform just needs to know the size of the type and which methods it has (including methods to get and set the data in the object). Roc exposes all of those via cffi. The platform doesn't even need to know the layout of the type.
I think we should be way closer to extreme n. Maybe even at extreme n. Extreme n does have a minor cost in perf due to there being no inlining between platform and app, but it removes tons of what makes the API brittle and hard to work with.
oh sorry I mainly meant zig as opposed to C
it makes sense that Roc would expose functions to the host, and that some of those would be implemented in the Roc code base using Zig
but I don't think we would need to change any internal implementations from Zig to C to facilitate any of that
Oh yeah, for sure not
Literally could make an exposed function for every builtin if we wanted. No need to implement anything in c for that.
yeah, basically we could look through every type that's exposed to the host and expose all the appropriate functions for it
and put them in their own sections so a linker can DCE any unused ones
and in a surgical linking future we could even do it lazily
actually I guess just preprocessing the host is enough :thinking:
like see which functions the host is dynamically linking in, and go generate them all (or give an error if it's asking for something that's malformed or shouldn't be exposed to the host)
that way we wouldn't waste time generating a ton of monomorphized functions that the host wouldn't even use in practice anyway
I guess with --no-link
you'd have to generate them all anyway, unless we gave --no-link
an optional host to analyze but not link
Yeah, exactly this. And I don't think we need to expose the full standard library just enough primitives to use each type. Host languages tend to have enough tools to deal with most things (like mapping folding, looping, etc)
yeah that makes sense to me! :+1:
is there anything blocking that? I can't think of anything
Not that I can think of.
As I said earlier, it could be done manually today by adding a ton more functions exposed to the host. Should be very doable to automatically generate them instead.
Was scanning zulip for some knowledge regarding the builtins when I came across this. Did this discussion produce a GH issue? Would be a shame to lose the conclusion.
I don't think we have an issue. But Brendan has mentioned a couple of times that he plans to work on this
Ah, thanks Luke, saw that thread when browsing, but it was in the additional projects section. It feels like @Brendan Hansknecht can do anything :big_smile:
Anything with the backend, maybe....I don't tend to touch anything type checker and up.
Last updated: Jul 06 2025 at 12:14 UTC