Stream: beginners

Topic: Tagged Unions as host


view this post on Zulip Max (Aug 21 2024 at 20:40):

Hi, I'm still trying to figure out some basic stuff about writing platforms, especially the mapping of data types. Right now, I'm using C to write a host. If mainForHost is a record type,

Type: { n: U64, str: Str }

say. I can treat it as a struct in my host.c

struct MyType {
  int n;
  struct RocStr str;
};

but what about union types. Lets say I have a mainForHost of type

MyUnion: [A Str (List MyUnion), Div (List MyUnion)]

how can I treat that in my host.c?

view this post on Zulip Brendan Hansknecht (Aug 21 2024 at 21:00):

int n; -> uint64_t n;

view this post on Zulip Brendan Hansknecht (Aug 21 2024 at 21:02):

myunion would be the union of a { RocStr; RocList} with a { RocList } with a trailing uint8_t for the tag.

view this post on Zulip Luke Boswell (Aug 21 2024 at 22:39):

One trick I use, is to make a super minimal platform.roc file and then use roc glue path/to/RustGlue.roc output/ platform.roc to generate the glue for it and then see what it looks like in Rust.

view this post on Zulip Luke Boswell (Aug 21 2024 at 22:39):

Here is RustGlue.roc https://github.com/roc-lang/roc/blob/main/crates/glue/src/RustGlue.roc

view this post on Zulip Luke Boswell (Aug 21 2024 at 22:40):

So the return type e.g. mainForHost is just whatever type I'm interested to know how roc handles.

view this post on Zulip Oskar Hahn (Aug 22 2024 at 07:12):

Here is an example

This is the c equivalent for [A U64, B]: https://github.com/ostcar/kingfisher/blob/b23e778dc5a56472d09b8319c1044138d2226141/host/roc/host.h#L19

As you can see, you need a struct and a union. The struct has two fields. The first field is the union, the second is one byte. The union contains all payload types and the byte decides, which one is active.

In your c code, you can look at the byte and then read the union value accordingly.

view this post on Zulip Max (Aug 23 2024 at 20:28):

Nice, to be honest, I did not even know about glue. Maybe I should have run roc --help at some point :D
Took me some time, but I was able to run the simple examples I was thinking of using rust now.
I will probably be using Rust now that it's starting to work for me. But out of curiosity, I would still like to get my c example to work. @Oskar Hahn I ran a copy of your [A U64, B] example successfully. However I can not seem to map that to my example. I can't even read the tag right. I get different values depending how long I make the string in the A. I'm sure I'm just missing something.

https://github.com/mx-ws/rocunion

view this post on Zulip Brendan Hansknecht (Aug 23 2024 at 21:35):

First glance that looks correct. But would need to take a deeper look.

view this post on Zulip Max (Aug 25 2024 at 13:19):

Thanks for looking at it and for all the answers then!

view this post on Zulip Brendan Hansknecht (Aug 25 2024 at 17:58):

Sorry for forgetting to circle back to this.

view this post on Zulip Brendan Hansknecht (Aug 25 2024 at 17:58):

There is definitely a compiler issue here.

view this post on Zulip Brendan Hansknecht (Aug 25 2024 at 17:59):

It seems that Roc doesn't understand that Lists create a separate allocation in a type definition

view this post on Zulip Brendan Hansknecht (Aug 25 2024 at 17:59):

MyUnion: [A Str (List MyUnion), Div (List MyUnion)]

Is being generated as if it where a recursive tag union. But it isn't. The Lists stop it from needing to be recursive

view this post on Zulip Brendan Hansknecht (Aug 25 2024 at 18:00):

So it is generating something roughly like:
MyUnion: Box [A Str (List MyUnion), Div (List MyUnion)]

view this post on Zulip Brendan Hansknecht (Aug 25 2024 at 18:19):

@Ayaz Hafiz since you're online, do you know where I would look in the source code to teach roc that List and Box break recursion when it comes to tag unions?


Last updated: Jul 06 2025 at 12:14 UTC