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

Unify output of atdgen -bs and atdgen -j #357

Open
bbenne10 opened this issue Oct 6, 2023 · 2 comments
Open

Unify output of atdgen -bs and atdgen -j #357

bbenne10 opened this issue Oct 6, 2023 · 2 comments

Comments

@bbenne10
Copy link

bbenne10 commented Oct 6, 2023

I'm currently writing a fullstack Reason application: Native code as the server (using Opium) and JS via Melange on the frontend.

Right now, the bucklescript output and json output do not have the same api. Notably, the _of_string and _to_string functions are missing from the bucklescript output, which makes transparent usage between the frontend and backend code impossible (or at least...much more verbose in the specific and impossible in the generic).

However, I think this could be done pretty trivially in the atdgen emitters. For instance, assuming the following saved as thing.atd:

type thing= {
  ~id <ocaml default="0">: int;
  foo: string;
  bar: int;
}

atdgen -j spits out these types (actual output modified for brevity):

type thing = Thing_t.thing = { id: int; foo: string; bar: int }
val write_thing :  Buffer.t -> thing -> unit
val string_of_thing : ?len:int -> thing -> string
val read_thing : Yojson.Safe.lexer_state -> Lexing.lexbuf -> thing
val thing_of_string : string -> thing

while atdgen -bs gives us the following:

type thing = Thing_t.thing = { id: int; foo: string; bar: int }
val read_thing :  thing Atdgen_codec_runtime.Decode.t
val write_thing :  thing Atdgen_codec_runtime.Encode.t

The string_of_thing and thing_of_string functions are extremely helpful, in that I can map over then in module entrypoint Thing.re to unify my interaction and abstract away usage of either YoJson.Safe.t or Atdgen_runtime.{Decode,Encode}.t entirely.

The generated function would be pretty trivial (note that it accepts len for parity with the atdgen -j output, but discards it):

let thing_of_string (~len=1024, input) =
  let json = Js.Json.parseExn input in
  let thing: Thing_t.t = Atdgen_codec_runtime.Decode.decode Thing_bs.read_thing json in
  thing

There are certainly things I'm overlooking here (Maybe the source of the underlying Js.Json type is a problem? since it will come from either ReScript or Melange? Maybe the tooling is a problem because we can't guarantee that Js.Json is available all the time in the runtime (since the rescript tooling is no longer ocaml native?)

@cyberhuman
Copy link
Contributor

cyberhuman commented Oct 9, 2023

what will be the unified signatures of _of_string and _to_string for type 'a foo = { bar : 'a }?

@bbenne10
Copy link
Author

bbenne10 commented Oct 9, 2023

I'm genuinely unsure. I hadn't considered that the type abstraction would mean you'd need a lexer to define what 'a would be... If it isn't obvious, my use case is not particularly generic (though that doesn't mean it shouldn't be taken into account).

Can we mirror the _j example and accept two lexers? Or just...not emit the functions in the ambiguous cases (maybe after emitting a warning to stdout)? I see the difficulty here, but I do think that there's benefit in the simple case to be able to hide the complexity a bit.

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

No branches or pull requests

2 participants