Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for different encodings for unions #6

Closed
Tarmil opened this issue Aug 6, 2019 · 6 comments
Closed

Add support for different encodings for unions #6

Tarmil opened this issue Aug 6, 2019 · 6 comments
Labels
enhancement New feature or request released: v0.4

Comments

@Tarmil
Copy link
Owner

Tarmil commented Aug 6, 2019

The current encoding for a value such as:

type Foo =
    | Foo of x: int * y: string
    | Bar

is what we can call Newtonsoft-like:

{ "Case": "Foo",
  "Fields": [ 123, "Hello world!" ] }

{ "Case: "Bar" }

I propose we add encoding formats like so:

type UnionEncoding =
  | AdjacentTag = 0x00_01 // 2-valued object: tag and fields (Newtonsoft-like)
  | ExternalTag = 0x00_02 // 1-valued object: tag is the field name
  | InternalTag = 0x00_04 // (n+1)-valued object or array: tag is inlined with the fields
  | Untagged    = 0x01_08 // n-valued object: tag is not stored 
  | NamedFields = 0x01_00 // whether fields are unnamed in an array or named in an object

This would give the following formats:

  • AdjacentTag: Newtonsoft-like.

    { "Case": "Foo",
      "Fields": [123, "Hello world!"] }
    
    { "Case": "Bar" }
  • AdjacentTag ||| NamedFields:

    { "Case": "Foo",
      "Fields": { "x": 123, "y": "hello" } }
    
    { "Case": "Bar" }
  • ExternalTag:

    { "Foo": [ 123, "hello" ] }
    
    { "Bar": [] }
  • ExternalTag ||| NamedFields:

    { "Foo": { "x": 123, "y": "hello" } }
    
    { "Bar": {} }
  • InternalTag: Thoth-like.

    [ "Foo", 123, "hello" ]
    
    [ "Bar" ]
  • InternalTag ||| NamedFields: WebSharper-like.

    { "Case": "Foo",
      "x": 123,
      "y": "hello" }
    
    { "Case": "Bar" }
  • Untagged: includes the NamedFields bit, since Untagged with unnamed fields doesn't really make sense. Deserialization is only possible if all cases have differently named fields and there's only one nullary case.

    { "x": 123, "y": "hello" }
    
    {}

The naming is shamelessly stolen from Rust's serde.

Note that when a field doesn't have an explicit name, F# automatically assigns the name "Item" if there is only one field, or "Item1", "Item2", etc if there are several fields.

The question of customizing the names of the fields "Case" and "Fields" should be resolved separately.

@Tarmil Tarmil added the enhancement New feature or request label Aug 6, 2019
@jbeeko
Copy link

jbeeko commented Aug 8, 2019

I would propose adding another option called BareFieldlessTags This will encode cases without any fields as just the case name. For example:

  • ExternalTag ||| BareFieldlessTags:
{ "Foo": [ 123, "hello" ] }

"Bar"
  • ExternalTag ||| NamedFields ||| BareFieldlessTags:
{ "Foo": { "x": 123, "y": "hello" } }

"Bar"

The motivation is when serializing Unions that represent a series of simple codes.

@Tarmil
Copy link
Owner Author

Tarmil commented Aug 8, 2019

That's a great idea!

@vilinski
Copy link

That's great to have a choice. But I don't need it for Options. its a special case from my sight. Should be just serialized to value inside of Some and None to null

@Tarmil
Copy link
Owner Author

Tarmil commented Aug 10, 2019

I think the best would be to do what you propose by default (ie Some stored as just the value; None is already stored as null), with an opt-out flag for people who need to distinguish between None and Some null (or Some None).

@vilinski
Copy link

Agree, though that's their fault if they model option of option or list of option, etc. :)

@Tarmil
Copy link
Owner Author

Tarmil commented Sep 30, 2019

Closing as this was released in v0.4 (the union issue is handled in #16).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request released: v0.4
Projects
None yet
Development

No branches or pull requests

3 participants