I think this is a complicated issue and I don't think Maybe/Option is the obvious answer. I think the downsides are subtle and nonobvious.
for example, a potential design we could consider is having encoding and decoding have a special concept of "optional" tag unions, which are defined as tag unions with exactly 2 tags, where one of them has a payload of exactly one value and the other has no payload (so, the same shape as Option/Maybe/etc.)
at that point, the json library doesn't need to be coupled to an Option or a Maybe type, and you can use more descriptive things in your data model than Some/None, e.g. Found/NotFound, Provided/Omitted, Present/Absent, Available/Unavailable, etc.
I don't love that idea.
I actually agree that being more specific is good. However there are a few big concerns i have with that.
Another option would be to just use a result right?
I do have some objections to that too
Just so we're clear I'm fully onboard with trying to find a better alternative and exploring solutions, but obviously thaey have to be better than the status quo, and I think being harshly critical is a good way to figure out if an idea is worth implementing.
I've also considered implementing option in terms of result, just with type aliases None:Err(None) and Some(a):Ok(a). I feel like that keeps error accumulation (if that's wanted) without having the weirdness of none being a failure. I don't like that much either. but it's a thought.
Should this maybe be moved to an ideas discussion? I don't have permissions to do that.
yeah those are all good points!
I think not having Option or similar in the stdlib has been great for return values, because it's so clear that all "this operation failed" APIs should standardize on one type and one way to do it
the main reasons I'm trying to find alternatives to Option for these use cases (which I certainly agree are important!) are:
? operator combined with the stdlib being consistent about this will be sufficient to prevent that from happening - e.g. "Why would I return Option? Then I miss out on ? and failure tag union accumulation!"but I think if we pull the trigger on adding Option to the stdlib, it will become entrenched and potentially better designs will never get explored properly.
one concrete design question: supposing we added support for a concept of "optional record fields" (not just default, but actually optional where if you omit the field when passing the record to a function, the function can actually tell at runtime whether the field was present or missing
if we had that, would we still want Option? If so, for what? e.g. JSON happens to make a distinction between "field was present but null vs field was missing" but does that matter from a decoding perspective? And does it matter from an encoding perspective if you can just tell the encode function "use null when I omit a field"?
19 messages were moved here from #contributing > Worklog (Draft PRs and coordination) by Jared Ramirez.
I definitely agree with you there! And I think in the short term a non-stdlib option type, in a package is the way to go. I think that makes it clear that its "a solution" not "the solution" and that things can change.
When writing the json decoder I would include a specific "json option" tag union with [null, undefined, value(a)]
And then also include an option to choose whether normal option becomes null (this should be the default), or undefined.
I think there are rare cases where you want granular control and we should provide it to you.
In fact maybe we should include an "encoding option" because many formats have a differnce between null and missing.
Yaml
Xml had XSI:null vs no tag
We could say "this will make a best effort to encode as whatever null is in your output langauge, but for some it may be the same as undefined"
As for optional record fields I think it would be great if there was a way to have optional fields that supported structural and nominal types. Restricting it to nominal types would make most deserialization and serialization require nominal types which I think would be a shame. I think if would reduce the use of structural types significantly. If they aren't at the edge of your code they likely just won't be used as much inside.
we had defaultable fields in structural records in the original Rust compiler, and my conclusion based on how it went is that it wasn't a good idea after all
does current roc have a 'spread' operator that would let you do a rust-style:
thing = Thing {
color: Red,
..Thing.default(),
}
https://github.com/roc-lang/roc/issues/7097
yes that is the plan I believe
updatedRecord = { foo: 123, bar: "abc", ..record }
Last updated: Feb 20 2026 at 12:27 UTC