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

Should it be possible to round-trip json? #368

Open
rbjorklin opened this issue Oct 18, 2023 · 5 comments
Open

Should it be possible to round-trip json? #368

rbjorklin opened this issue Oct 18, 2023 · 5 comments

Comments

@rbjorklin
Copy link

rbjorklin commented Oct 18, 2023

I was caught by surprise when trying to round-trip some json following this example in the documentation. Is round-tripping supposed to work?

let json = "{\"ID\":12345678,\"username\":\"kimforever\",\"background_color\":\"black\"}";;

let profile = Profile_j.profile_of_string json;;

let round_tripped_json = Profile_j.string_of_profile profile;;

(* "{\"ID\":12345678,\"username\":\"kimforever\",\"background_color\":<\"black\">}" *)

Notice how "black" comes back as <\"black\">.

The same behaviour is also present when using <ocaml repr="classic">.

@cyberhuman
Copy link
Contributor

Can you try compiling the atd with -j-std? (IMO it should be the default)

@rbjorklin
Copy link
Author

rbjorklin commented Oct 18, 2023

Yeah that fixed it! Thanks for the quick response @cyberhuman! This feels like it might be worth a mention somewhere close to where variants are shown.

EDIT: Now that I know what I'm looking for I found the relevant documentation. Unfortunately I have no good suggestion for how to make this more discoverable.

@mjambon
Copy link
Collaborator

mjambon commented Oct 18, 2023

Can you try compiling the atd with -j-std? (IMO it should be the default)

Yes. The only issue is backward compatibility. We might want to release this as part of a major version release. I started a list here.

@rbjorklin
Copy link
Author

On the topic of round-tripping is there a way to work-around this behaviour?

my_type.atd:

type my_type = {
    my_number : float;
    my_key : string;
}

my_type_test.ml:

let t = My_type_t.{ my_number = 65.26; my_key = "ABC" }

let () = 
   Printf.printf "%f" t.my_number;
    (* Prints: "65.260000" *)

    Printf.printf "%s" (My_type_j.string_of_my_type t)
    (* Prints: "{\"my_number\":65.26000000000001,\"my_key\":\"ABC\"}" *)

I would be okay parsing my_number into a string as long as I can round-trip it to a json number while maintaining the number of significant figures.

@mjambon
Copy link
Collaborator

mjambon commented Oct 19, 2023

It's best to open a new issue for each new question.

Printing 65.26 instead of 65.26000000000001 while maintaining correctness is difficult or computationally expensive. Atdgen prints enough decimals to ensure that parsing the string representing the float will result in the original float. In this case, you can see that it works:

utop # 65.26 = 65.26000000000001;;
- : bool = true

The internal representation of OCaml floats or C doubles (IEEE-754 binary-64) is binary rather than decimal and provides no clue that there's a short decimal representation for the number. Printing a sufficiently large number of decimal digits (17 digits or so) ensures that parsing the string in decimal notation will recover the original float.

Maybe there are tricks we could use to print 65.26 as 65.26 correctly and cheaply but I'm not an expert in this field and I'm not aware of such tricks.

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

3 participants