Stream: beginners

Topic: Record with default empty Dict


view this post on Zulip Aurélien Geron (Aug 21 2026 at 05:58):

I tried using Dict.empty() as the default value in a record:

main! = |_| {
    rec : { foo : Dict(U64, U64) ?? Dict.empty() }
    rec = {}
    dbg rec
    Ok({})
}

Unfortunately, I get the following error:

── ✗ default value must be a literal ───────────────────────────────────────────────────────────── test_default.roc:2:37

The default value for the foo field is not a literal.

rec : { foo : Dict(U64, U64) ?? Dict.empty() }
                                ^^^^^^^^^^^^

A field default (??) is materialized by the compiler at every construction site that omits the field, so it must be a literal: a number, an interpolation-free string, a tag, or a list, record, or tuple built only from literals. Anything that
refers to another value could form an evaluation cycle the compiler will not chase.

The error is pretty clear, but I'm wondering whether there might be a workaround? Maybe some way to force the compiler to evaluate Dict.empty() at compile time, or maybe another way to build an empty Dict?

view this post on Zulip Aurélien Geron (Aug 21 2026 at 06:03):

I guess I could make the field entirely optional, then default to Dict.empty() whenever I try to access it:

main! = |_| {
    rec : { foo ?: Dict(U64, U64) }
    rec = {}
    rec_foo = rec.?foo ?? Dict.empty()
    dbg rec_foo.len()
    Ok({})
}

I guess that's ok, but I'm still wondering whether there's another way?

view this post on Zulip Luke Boswell (Aug 21 2026 at 06:10):

I really haven't explored this new optional record feature at all

view this post on Zulip Aurélien Geron (Aug 21 2026 at 06:11):

Interestingly, the following code fails as well, but if I replace MySet.empty with MySet.([]), then it works.

MySet(a) :: List(a).{
    empty = MySet.([])
}

main! = |_| {
    rec : { foo : MySet(U64) ?? MySet.empty }
    rec = {}
    dbg rec
    Ok({})
}

view this post on Zulip Aurélien Geron (Aug 21 2026 at 06:29):

I also ran into an issue with a List of records containing default fields when they don't all use the same set of fields. I filed issue #10886.

view this post on Zulip Krzysztof Skowronek (Aug 21 2026 at 10:00):

this smells like python default args being static - fight it with fire! at least in Roc they are immutable, to it's not a problem

IMO your first version should be acceptable - I wonder what it is about Dict.empty() that makes it not a literal

view this post on Zulip Richard Feldman (Aug 21 2026 at 11:23):

it's just a limitation of the initial implementation of optional record fields - @Jared Ramirez commented on another thread that arbitrary expressions should work in the future :smile:

view this post on Zulip Jared Ramirez (Aug 21 2026 at 13:01):

yup! i have a PR that’s almost ready that relaxes this restriction!

view this post on Zulip Aurélien Geron (Aug 22 2026 at 22:46):

Btw, Dict and Set were missing to_inspect, so I just added them in PR #10900: can someone please review it?
The output format looks like "Set.from_list([4,3,2,1])". I think it's useful to be able to copy/paste the Str.inspect output to the REPL.

view this post on Zulip Anton (Aug 24 2026 at 12:43):

I vaguely remember we did not want people to depend on the order of the output.
Is it ok to add to_inspect to Dict and Set @Richard Feldman?

view this post on Zulip Richard Feldman (Aug 24 2026 at 15:23):

yep! fold and iter for those have a deterministic order based on insertion order, regardless of hashing function

view this post on Zulip Richard Feldman (Aug 24 2026 at 15:25):

so I think it should even still be the case that if we make the output be "Set.from_list(...)" and then you put that Set.from_list call back into the repl, it should give the same output

view this post on Zulip Aurélien Geron (Aug 24 2026 at 20:00):

Yeah, I was wondering about that too. I just checked: it looks like the order remains the insertion order even after removing/inserting items. I thought that this might mess up the order, but it doesn't.

view this post on Zulip Richard Feldman (Aug 24 2026 at 20:07):

yeah that's very much by design! :smiley:


Last updated: Sep 03 2026 at 15:16 UTC