Does composing JSON stringify with JSON parse always return the same type in ReasonML?


#1

Hello,

If I had some type and decided to stringify it and then parse it again. Would it in ReasonML always return the same type or are there special types/cases where this is unsafe?


#2

ReasonML types uses JS types under the hood so all principles are the same. Depends on what are you trying to do with the stringified version, it maybe safe or not.

Some things to watch out for:

  • Can’t stringify functions
  • the underlying data structure could be different between different compiler versions

#3

The use case is sending data between client/server in Reason for an application. It saves a bit of boilerplate when you don’t have to manually write encoders/decoders.

But then, if I understand it correctly, it should be safe to send things like Maps, Sets, Lists et.c.


#4

yeah. that would be fine if both backend and frontend share the same types and are compiled with the same compiler version. Just don’t store this information permanently somewhere.


#5

for the original question Set’s (and I believe also Maps and and WeakMap’s) don’t work well together with JSON stringify/parse.

image


#6

ReasonML’S sets and maps works well with JSON.stringify


#7

Ah, ok! :ok_hand:


#8

In short, that is unsafe. If you look at it purely from the types, then you have:

// Js.Json
let stringifyAny: 'a => option(string)
let parseExn: string => t

So even purely from the type system perspective, any data that you stringify does not remember its original Reason data type (since those don’t exist at runtime), it is encoded as purely the string rendering of a JSON blob. Any string you parse into a Js.Json.t JSON blob will need to be further decoded into your specific type.

Anyway, since you just want to save boilerplate writing encoders and decoders, I recommend checking out https://github.com/ryb73/ppx_decco , which can automate that for you.


#9

Note that for bucklescript, any Variant type e.g. Some(x) will break if you pass it through JSON.stringify, as the tag on the value is not represented in the JSON.
For functions that will correctly compose for bucklescript, check out this PR: https://github.com/BuckleScript/bucklescript/pull/3058