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

Encoding of variants with no args #32

Open
zoggy opened this issue Jun 16, 2015 · 12 comments
Open

Encoding of variants with no args #32

zoggy opened this issue Jun 16, 2015 · 12 comments

Comments

@zoggy
Copy link
Contributor

zoggy commented Jun 16, 2015

Hello,

By now, variant constructors with no arguments, for example Foo in type t = Foo are encoded as
List [`String "Foo"]`. Would it be possible to encoded these as just String "Foo"` ? (and read them back from the same way, of course).

The reason is that it is quite heavy to have to put them in a list. I encouter the problem when wanting to use generated JSON encoder/decoder functions in Ocf wrappers.

@whitequark
Copy link
Collaborator

Sure, the change is trivial. The reason it is done like so is for consistency. Also, changing the format will require either a major version bump or a setting, so I'm a bit reluctant to.

Can you give an example of the kind of friction you encounter while trying to use thee with Ocf wrappers?

@zoggy
Copy link
Contributor Author

zoggy commented Jun 16, 2015

Suppose I want to store a list of "tags" in an option, I can do:

type tag = Foo | Bar | Gee [@@deriving yojson]

let tag_wrapper =
   let to_ = tag_to_yojson in
   let of_ ?def x =
     match tag_of_yojson x with
     | `Ok tag -> tag
     | `Error _ -> Ocf.invalid_value x
   in
   Ocf.Wrapper.make to_ of_

let option_tags = Ocf.list tag_wrapper []

let () =
  let g = Ocf.add Ocf.group ["tags"] option_tags in
  Ocf.from_string g
    {|
      { tags: [ ["Foo"],  ["Bar"] ] }
    |};

The JSON code to represent my list of tags is unnecessarily heavy. Of course, I can create my own JSON coder/decoder for such simple variants, but I wanted to benefit from the ppx_deriving_yojson.

In the case where the tag type is an open type, using the code generated by ppx_deriving_yojson would be much easier than re-implementing the reference mechanism to handle variant constructors added later in the program.

@zoggy
Copy link
Contributor Author

zoggy commented Jun 16, 2015

Maybe an additional attribute for the type could allow to indicate to encode variants with no arg in a single string ?

@whitequark
Copy link
Collaborator

Maybe something like [@@deriving yojson { flat_variants }] ?

@zoggy
Copy link
Contributor Author

zoggy commented Jun 16, 2015

That's nice.

@hcarty
Copy link
Contributor

hcarty commented Aug 10, 2015

This would also be nice to have for compatibility with atdgen.

@foretspaisibles
Copy link

I think we should consider two cases:

  1. The case where the sum type is an enumeration, that is, consists of a list of constant constructors.
  2. The case where the sum type is mixed, that is, has constant constructors and not constant constructors.

In my experience with various JSON/HTTP restful APIs, the most common use case of a flat encoding of variants would be the case of enumerations. For me, it would fill the bill to be able to decorate an enumeration with a tag

[@encoding enumeration]

or something similar, to inform ppx_deriving that the type is an en enumeration (if not that is an error) and should be encoded as a string, rather than as a list of objects.

@zoggy Would it fit for you as well?

@zoggy
Copy link
Contributor Author

zoggy commented Dec 16, 2015

Hum, not completely, as I would like to have the encoding as a string for constant constructors even for a type with some not constant constructors.

@foretspaisibles
Copy link

IIYRC this means that you have to deserialise json like

[
  "Regular",
  { kind: "Outlier", weight: 6 }
]

as

[| Regular; Outlier(6) |]

Right?

Just out of curiosity, where do practical examples of this live? Is there any widely used JSON/HTTP RPC API using such encodings?

@zoggy
Copy link
Contributor Author

zoggy commented Dec 16, 2015

What I mean is, with a type t and values v and u defined as

type t = Foo | Bar of int
let v = Foo
let u = Bar 3

The JSON representation of v would be "Foo" and the one for u would be ["Bar", 3].

@zoggy
Copy link
Contributor Author

zoggy commented Dec 16, 2015

Regarding your request about examples, this is not related to any JSON API, but for writing by hand some configuration files.

@hongchangwu
Copy link
Contributor

One way to make this work without breaking backward compatibility is to introduce a new attribute (e.g., [@enum]). The [@enum] attribute is only valid on empty variant constructors.

type t = 
  | Foo [@enum]
  | Bar of int
  [@@deriving yojson]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants