-
Notifications
You must be signed in to change notification settings - Fork 465
Add a non-abstract @bs.deriving
for records
#4444
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
Comments
Can you describe how this would work in code? It would be awesome to have a non-abstract There is also another use-case for dealing with JSON. Sometimes you'd like the keys to be hidden when having a JSON compatible data structure. But in other cases you'd want the None keys to be explicitly |
I think the following are interesting solutions:
This could look like this:
would compile to
|
Incidentally this make a lot of sense for a number of libraries. For instance in the |
Yes, all this was written with very limited knowledge of bucklescript internals, I have no idea if it's possible to have hidden-field objects to represent records and if the two representations are interchangeable for Bucklescript. What I had in mind was that the following code: module Foo =
struct
type t = {
foo: int option [@bs.optional ];
bar: int option;
baz: string;
} [@@bs.deriving]
end
let foo = Foo.t ~bar:None ~baz:"baz" () would produce: module Foo :
sig
type t = private {
foo: int option;
bar: int option;
baz: string;}
val t : ?foo:int -> bar:int option -> baz:string -> unit -> t
end =
struct
type t = {
foo: int option;
bar: int option;
baz: string;}
let t ?foo ~bar ~baz () = (* generated creator function *)
end
let foo = Foo.t ~bar:None ~baz:"baz" () that would be compiled in JS to: var foo = {
bar: undefined,
baz: "baz"
}; |
This is bad for performance of generated code — you want shape to be fixed. I am thinking we only apply flexible shapes for very large object which contains more than ten optionals |
Supporting sparse records with threshold could be good. (Based on the number of fields or perhaps just the number of optional fields). And perhaps let people override the heuristic too. |
Overriding the heuristic would indeed be great, as the behavior slightly changes (js dependencies can check for keys instead of checking if the value is undefined). |
This is one should really be clean up: It would be great to remove the magic: drop both |
Is it bad for performance when creating a record or when using it? If we want finer control on performances, maybe we can have two different annotations, one that would just generate a creator function and one for hiding the fields. |
I think we can close this thanks to #5423. |
Sort of. Optional fields specified as that’s the one thing deriving abstract and @obj did that optional fields don’t do. |
Are you sure @TheSpyder? type t = {
name: string,
age?: int,
}
let foo = {
name: "foo",
age: ?None,
}
let makeFoo = (name, age) => {
name,
?age,
}
let foo2 = makeFoo("foo2", None) compiles to: // Generated by ReScript, PLEASE EDIT WITH CARE
'use strict';
function makeFoo(name, age) {
return {
name: name,
age: age
};
}
var foo2 = {
name: "foo2"
};
var foo = {
name: "foo"
};
exports.foo = foo;
exports.makeFoo = makeFoo;
exports.foo2 = foo2;
/* No side effect */ cf playground |
WIthin a single scope, they are equivalent. But when you have cross-scope functions such as this one the problem becomes apparent:
In some JS contexts there is unfortunately a difference between a value not set and it being set to undefined. |
BS7 record as object representation led to much easier bindings, but two use cases are not covered by this new representation:
undefined
fields)Today, these two use cases are covered by the use of
@bs.deriving abstract
or@bs.obj
annotations, but that makes the target type abstract, which removes the ability to use the very convenient features of records in OCaml like pattern matching.Having a non-abstract
@bs.deriving
annotation that would keep the type as record would bring the best of both worlds and would make@bs.deriving abstract
or@bs.obj
annotations almost useless.An optional
private
subannotation ([@bs.deriving private]
) would make the type private and would force the use of the generated creation function to create a record of this type (for JSON-compliant objects for example).A safer approach would be to make the type
private
by default and to provide apublic
ornon-private
subannotation to opt-out this effect.The text was updated successfully, but these errors were encountered: