As an uninformed newbie coming from Rust/TS/Clojure I've been following along with the encoding/decoding discussions and I think doing the non-happy path decode in one step is creating friction in the solutions. I'd be inclined to model it like this using TS syntax (which is a crazy type system but can express the idea):
type SerdeField<T> = Val<T>|Null|Omit
type Serde<T, K extends keyof T> = { [key: K]: SerdeField<typeof T[K]> }
function decodeToSerde<T>(bytes: U8[]) -> Serde<T>
function tryInto<T, S extends Serde<T>>(serde: S) -> Result<T, DecodeError>
// Conceptually...but a real encoder would probably special case to avoid intemediates
function decode<T>(bytes: U8[]) -> Result<T, DecodeError>
decode = bytes => tryInto(decodeToSerde(bytes))
For the decoding problem specifically you could do a SerdeField<T>[] like it works in Rust but I don't know how to do the encoding side without manually writing what would be auto-derived in Rust or an iteration over keys in Clojure/TS.
Leaving the specifics of encoding/decoding behind, I think this pattern is generally useful. As a specific example, I really like the request guards pattern used in various Rust frameworks but I don't think that's doable in Roc without external code generation or maybe platform level trickery(?). Another use case would be for validation without manually writing the field checks individually.
I do realize that this opens up the large can of metaprogramming worms that works against Roc's general philosophy and I strongly suspect it's impractically large for a feature request. I bring it up in case I've overlooked something or someone can point me to a pattern I don't know but if not then at least the idea is out there.
Tangent: As I wrote this, it occurs to me that there might be some minimal level of useful metaprogramming which would be this pattern, Traits (I think they're Abilities here?) and function arguments as a record. Ignoring language extensions and syntax tweaks, the only use case I can think of that wouldn't be covered is compile time type checking for DB query strings. My typed functional experience is limited to F# but I could do computation expression bind/return onto that last part so it probably runs afoul of the anti-HKP philosphy in the FAQ. So maybe this isn't such a good idea...maybe someone will find it interesting.
Karl said:
I think doing the non-happy path decode in one step is creating friction in the solutions
hm, can you say more about this? :thinking:
That's mostly regarding the expanding optional record fields discussion that seems to be motivated by the decoding stuff. Maybe there's a use case elsewhere but I couldn't immediately come up with one. This started as a "why don't they just do it like Serde" post on that topic but that seemed well off topic and it jumped through a couple hops and turned into this. Sorry about that.
haha no worries! :big_smile:
In re-reading the first part it might not be clear that I'm looking for some what to process each field of a record and get out another record with the same fields but different types without having to write out individual field access. There isn't some pattern for this that I'm missing, right? As an example, I found the builder pattern example to be something that doesn't fit into my experience.
Last updated: Jun 16 2026 at 16:19 UTC