Stream: beginners

Topic: dynamic access to Record fields and Tuple items in Roc


view this post on Zulip Minato 13 (Dec 07 2025 at 01:34):

Hi, I installed ROC today and started playing around a bit to try to learn the language, and I’m finding it really interesting so far.

I got a question about how to access a Tuple or a Record based on a variable, for example:

record = { foo: "bar", fizz: "buzz" }
key = "fizz"
# how can I access the field based on the value of `key` without hardcoding record.fizz?
tuple = ("foo", "bar")
index = 1
# how can I access the element at `index` in the tuple using the variable `index`
# without hardcoding tuple.1?

view this post on Zulip Brendan Hansknecht (Dec 07 2025 at 03:21):

You have two main options

view this post on Zulip Brendan Hansknecht (Dec 07 2025 at 03:21):

One, use different data structures for dynamic acces. Instead of a record, use a dictionary. Instead of a tuple, use a list.

view this post on Zulip Brendan Hansknecht (Dec 07 2025 at 03:22):

Two, write a mapping function for access. (Though maybe we should autogenerate this for tuple at least).

view this post on Zulip Brendan Hansknecht (Dec 07 2025 at 03:24):

Something like (I hope this is the right syntax for match):

getTup = |tup, index|  {
    match(index) {
        0 => Ok(tup.0),
        1 => Ok(tup.1),
        _ => Err(OutOfBounds),
    }
}

view this post on Zulip Brendan Hansknecht (Dec 07 2025 at 03:24):

Can do something equivalent for the string keys and the record.

view this post on Zulip Brendan Hansknecht (Dec 07 2025 at 03:25):

Oh, one other note for these. You can also use lambdas.

view this post on Zulip Brendan Hansknecht (Dec 07 2025 at 03:25):

So .foo should give you a function to extra the foo field from a record. Some with .1 for a tuple.

view this post on Zulip Brendan Hansknecht (Dec 07 2025 at 03:25):

That might also be enough for your use case.

view this post on Zulip Norbert Hajagos (Dec 07 2025 at 06:48):

+1 to what Brendan has said. Roc doesn't have runtime type information, so when you want to do something truly dynamic (e.g. you read a string from stdin and you access record.<str-content-here>, in JS it would be record[strContent]), you have to do the mapping at compile time (Brendan's getTup is like that), or you need a datastructure that will do that mapping for you at runtime.

In hindsight I see, I've gone way overboard with this answer. Don't worry, you don't have to understand this to use roc.

A record is just like a tuple in Roc, except the fields have a "proper" name, not just numbers. They are both like a C struct if you're familiar with them. Your record var will take up 48 bytes. 24 for each of the 2 strings. A string is 8+8+8 bytes on your system (A pointer to the start of the string, a length and another number that helps with managing its memory). These 2 strings are just one-after-another when your program executes and the interpreter doesn't know what the name of each field in your source code was. For that, it would have to store those names as well, making the struct double its size. You could imagine a simple algorithm running on record[strContent] that would search for strContent in the record's list of fieldnames and when it finds it (if it finds it), returns the value with the same index. But that wouldn't be enough either, because if you have a record = { foo: "bar", fizz: True, buzz: False }, record takes up (24+1+1) bytes, 1 byte for each boolean. There it's not enough to say "get the 3rd element", because how do you know where that is? It is at offset byte 25 (zero-indexed) from the start of the struct, but for that to be dynamic, we would have to know at runtime how big each of the fields are (runtime type information), so that we could do the calculation of "it starts at offset 24+1". All that to say, structs are not dictionaries that have all this machinery in them, but we have (will have once implemented) Dict-s that handle this use case. They are also nicer in that they handle the case when there isn't such key as you have provided, while structs and tuples will only access fields that are guaranteed there.


Last updated: Dec 21 2025 at 12:15 UTC