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 `serializeAnyToJson` and `unserializeAnyFromJsonUnsafe` #3058

Open
wants to merge 3 commits into
base: master
from

Conversation

@jaredly
Copy link
Contributor

commented Sep 23, 2018

See docs for more info. This also retains debug information if bsc was
with with -bs-g.

This is basically parallel in spirit to OCaml's "input_value" and "output_value", but specialized to the javascript use-case.

[anyToJson value] turns any [value] into a JSON object

This will throw an error if there are any functions anywhere in the value.

[unsafeAnyFromJson json] converts a serialized JSON object back into the bucklescript runtime value.

Warning: marshaling is currently not type-safe. The type of marshaled data is not transmitted along
the value of the data, making it impossible to check that the data read back possesses the type expected
by the context. The return type of this function is given as 'a, but this is misleading: the returned
OCaml value does not possess type 'a for all 'a; it has one, unique type which cannot be determined at
compile-time.

The programmer should explicitly give the expected type of the returned value, using the following syntax:

  (Js.Json.unserializeAnyFromJsonUnsafe json : type)

Anything can happen at run-time if the object does not correspond to the assumed type.

Test Plan:

make libs
make -C jscomp/test all
./node_modules/.bin/mocha jscomp/test/js_json_test.js

jaredly added some commits Sep 6, 2018

Add `serializeAnyToJson` and `unserializeAnyFromJsonUnsafe`
See docs for more info. This also retains debug information if bsc was
with with `-bs-g`.

```
[anyToJson value] turns any [value] into a JSON object

This will throw an error if there are any functions anywhere in the value.

[unsafeAnyFromJson json] converts a serialized JSON object back into the bucklescript runtime value.

Warning: marshaling is currently not type-safe. The type of marshaled data is not transmitted along
the value of the data, making it impossible to check that the data read back possesses the type expected
by the context. The return type of this function is given as 'a, but this is misleading: the returned
OCaml value does not possess type 'a for all 'a; it has one, unique type which cannot be determined at
compile-time.

The programmer should explicitly give the expected type of the returned value, using the following syntax:

  (Js.Json.unserializeAnyFromJsonUnsafe json : type)

Anything can happen at run-time if the object does not correspond to the assumed type.
```

Test Plan:
```
make libs
make -C jscomp/tests all
./node_modules/.bin/mocha jscomp/test/js_json_test.js
```
@bobzhang

This comment has been minimized.

Copy link
Member

commented Sep 23, 2018

I remember that @cristianoc had something similar.
It is something very useful, my concern is that does it have to be distributed with the compiler or it could be distributed as a third party library? I would prefer it to be distributed as a third party if possible since it would reduce the maintenance overhead

@jaredly

This comment has been minimized.

Copy link
Contributor Author

commented Sep 24, 2018

I think it's important that it be distributed with the compiler because it's dependent on the runtime representation of types (as defined by the compiler). So if the representation changes, then this would need to change. Also this is a thing that everyone asks for, and it would be great to bake it in.

@cristianoc

This comment has been minimized.

Copy link
Contributor

commented Sep 24, 2018

@jaredly here’s the serialization code I have written: https://github.com/cristianoc/REInfer/blob/master/src/Serialize.re

There are a couple of special cases there: such as respecting the distinction between null and undefined.
There are some tests too, that serialize followed by deserialize gives you the same thing back (for things handled in that project). I could run the tests on your serializer.

@bobzhang

This comment has been minimized.

Copy link
Member

commented Oct 1, 2018

I suggest we may consolidate our work in a third party library(with full coverage test, since it is fragile code). I am okay to have it merged if someone is willing to provide committed maintenance

@chenglou

This comment has been minimized.

Copy link
Member

commented Oct 9, 2018

What can we do to prevent accidentally forgetting the annotation for unserialize?

@jaredly

This comment has been minimized.

Copy link
Contributor Author

commented Oct 10, 2018

I called it Unsafe to try to help that :) if we wanted to get into the linting business (which is something I've been thinking about recently, actually), we could easily lint against unserializeAnyFromJsonUnsafe not being wrapped in a type constraint

@htzh

This comment has been minimized.

Copy link
Contributor

commented Oct 31, 2018

@jaredly Is this solution to provide a native/portable version of Js.Json.stringifyAny? For js target stringifyAny seems to work well. For deserialization I just read back the data in js and declare it [@bs.val] external data: someDataType = "";.

@htzh

This comment has been minimized.

Copy link
Contributor

commented Oct 31, 2018

@jaredly @bobzhang I now realized this proposal is for JS specialization. Is there a true advantage over Js.Json.stringifyAny? stringifyAny maps to the browser native implementation stringify and is therefore zero maintenance.

@arnarthor

This comment has been minimized.

Copy link
Contributor

commented Nov 13, 2018

@htzh yes, this would preserve the types on both ends because Bucklescript does some things in the compiled code that isn't part of JSON stringify. For example it augments arrays with a .tag attribute for Variants and some similar container types.

As soon as you try to send a Variant to the server with Js.Json.stringifyAny, it looses it's type information so the server won't be able to reliably pattern match on that Variant after doing Js.Json.parse

By using the proposed functions, you could share types between client and server and not have to write any bindings on either side since these functions would convert these data types to the same JS format that the compiler uses to identify types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
6 participants
You can’t perform that action at this time.