Hey folks,
I'm wondering whether there's a plan to implement some (or all) of the record features that existed in the old Roc in the new compiler?
In particular, I miss the fields with default values, such as {a, b ?? 0}. These are quite handy for default arguments (in fact, several Exercism exercises use these).
I don't think I've ever used wildcard records or constrained records, but I'm just curious to know what the plan is.
removing default-field records from structural records was intentional (there were a lot of edge cases problems in type-checking that we never figured out how to solve, or whether they were solvable), but actually we could do that feature in nominal records, now that we have those
we haven't properly discussed the idea though - do you have any motivating examples from Exercism exercises where they came up?
They mostly came up in constructor arguments for opaque types. Basically complex types that you may want to create in various ways. Without default arguments we either need to create multiple new functions, or the type user has to pass all the default arguments manually.
I think that's about it in Exercism, but in libraries it's quite useful when a function has a bunch of options, for example HTTP requests: you don't want to have to pass the default arguments every time. I guess this second use case can be reduced to the first one by passing an Options record as an argument, so the problem becomes how to create this Options record.
Perhaps we could go the Rust way, e.g.:
HttpParams := {method: Str, cookies: List(Str), ...}.{
default : HttpParams
default = {method: "GET", cookies: [], ...}
}
request : HttpParams -> HttpResponse
request = |params| { ... }
Then the user can write:
request({ ..HttpParams.default(), method: "POST"})
Perhaps that's fine. Maybe a bit of syntax sugar could help though.
ah! so the idea for config like this was to use static dispatch "builder" style
Ah cool, I remember learning about builders, but I kind of forgot. I'll look into it again. :+1:
so like:
HttpParams.post().headers([...])
and then chain methods on top for whatever other customizations you want
That makes sense
This covers the "complex type creation" problem very nicely.
I guess the other use case is simple functions such as is_approx_eq which can have one or two arguments that you usually don't want to change, but which can occasionally be handy. You don't really want to have to set these arguments explicitly every time.
In the old Roc, the signature was is_approx_eq : Frac a, Frac a, { rtol ? Frac a, atol ? Frac a } -> Bool.
Most of the time you want to write is_approx_eq(3.14159265, pi), without having to set rtol and atol.
yeah, maybe those could become two different functions (e.g. one ends in _with)
2 functions instead of 1, but then you don't have to use the record braces in the common case
is_approx_eq(3.14159265, pi, {atol: 1e-5, rtol: 1e-8})
is_approx_eq(3.14159265, pi, Approx.default)
is_approx_eq(3.14159265, pi, Approx.atol(1e-5))
Cool, I'll keep thinking about this, but I like the builder + function variants when needed.
awesome, sounds good!
Last updated: Jun 16 2026 at 16:19 UTC