Stream: API design

Topic: Encode with list manifesting


view this post on Zulip Brendan Hansknecht (Jul 08 2024 at 01:41):

I am looking at the encode and decode api rn. One thing I quite dislike is that record and tuple encoding requires manifesting a list. On top of that, the record encoder forces generating a string name, but many encoders (especially for binary formats) will never use the field name. Given the api is getting update, I was thinking it would be good to iron this out as well.

Specifically these 3 functions:

    record : List { key : Str, value : Encoder state } -> Encoder state where state implements EncoderFormatting
    tuple : List (Encoder state fmt) -> Encoder state where state implements EncoderFormatting
    tag : Str, List (Encoder state fmt) -> Encoder state where state implements EncoderFormatting

Can we somehow do this in a polling format where instead of manefesting the list, we load one element at a time. With that we can also separate loading the record field name from loading the record field encoder.

Any thoughts?

view this post on Zulip Brendan Hansknecht (Jul 08 2024 at 01:59):

Oh, looks like serde has answers again:

add a separate method for encoding fields from encoding the wrapper type.
Then build up the record like so:

let mut rgb = serializer.serialize_struct("Rgb", 3)?;
rgb.serialize_field("r", &self.r)?;
rgb.serialize_field("g", &self.g)?;
rgb.serialize_field("b", &self.b)?;
rgb.end()

Not 100% sure how all the types work out and how this maps, but feels quite doable.

view this post on Zulip Brendan Hansknecht (Jul 08 2024 at 02:03):

Maybe for roc, this mean that Encode.record would take a lambda to add fields:

I noticed that we don't actually name our records unlike serde. Not sure if that is something we want to add or not. Given are types aren't nominal, it feels unimportant. Though might matter for opaque types or certain serialization formats?

encodeRgb = \{r, g, b} ->
    size = 3
    Encode.record "name?" size \state, addField ->
        state
        |> addField "r" r
        |> addField "g" g
        |> addField "b" b

view this post on Zulip Brendan Hansknecht (Jul 08 2024 at 02:04):

hmm, not user that actually would typecheck. Cause each field could have a different type. So each field might need to monomorphize addField differently.

view this post on Zulip Brendan Hansknecht (Jul 08 2024 at 02:05):

oh wait, this should work:

encodeRgb = \{r, g, b} ->
    size = 3
    Encode.record "name?" size \state ->
        state
        |> Encode.recordField "r" r
        |> Encode.recordField "g" g
        |> Encode.recordField "b" b

Cause Encode.recordField can now monomorphize for each field uniquely.

view this post on Zulip Brendan Hansknecht (Jul 08 2024 at 02:16):

That said, this api still feels off a bit. Maybe it is good though.


Last updated: Jul 06 2025 at 12:14 UTC