-
Notifications
You must be signed in to change notification settings - Fork 465
bs.deriving abstract
: start with a record type or a creator function?
#2680
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
This is cool because it might make the native interop story better. Right now to talk to any C or objc library you need to write some C code that will translate the data structures around, or that will allow you to access the different fields you need. Generally I’m not sure how we’ll do this on the native side of things, because we need type information (I think?) to generate the right C code. |
The original record will be completely erased. For the ocaml native ppx, it would be straightforward. I did not think about C FFI, but it could be useful. Note it is more useful than getter/setters.
We will change |
oooh I quite like the "start from creator function" -- providing easy defaults & obvious optionals feels like a total win. I guess the main downside is missing mutability? |
Definitely prefer the creator function option because I see the record type as a big negative. If it gets erased then It'll be distracting to have it as the only representation visible. |
The creator function looks pretty clean. Perhaps one can control mutability
with dedicated attributes.
…On Tue, Mar 27, 2018 at 7:02 PM, Ricky Vetter ***@***.***> wrote:
Definitely prefer the creator function option because I see the record
type as a big negative. If it gets erased then It'll be distracting to have
it as the only representation visible.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#2680 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AHmKl6wREkQl-q9oCpIMUBI4I2p1qr-Lks5tinCngaJpZM4S8att>
.
|
Note it is not just syntax. The semantics is isomorphic to record, type ( + 'a, - 'b ) t = {
mutable a : 'a ; (* The compiler will complain about the variance of 'a *)
b : 'b ;
} [@@bs.deriving abstract] Also it is pretty neat to provide more access control: module S : sig
type t = private { a : int } [@@bs.deriving abstract]
end = struct
type t = {mutable a : int; b : int } [@@bs.deriving abstract]
end In the implementation, we use the isomorphic record types for various checking, lie variance check, but it will be erased after such checks. So its syntax is similar to creation function, but its semantics is isomorphic to record |
That's gonna be even more confusing to newcomers I feel; whereas the creator function doesn't confuse. I'll amend the post with your other points |
Note this is not really FFI. |
I guess at least you can merge default value and bs.optional? Don't want too many new tags. I maintain that having a record there is very confusing for folks though. Especially since it's already confusing that records are nominally types and can't be found globally, etc. Folks expected their record value usage to magically "just work" |
More precision: default value in general is hard to support either way; currently the creation function is inlined (doesn't generate any function actually), so 100% free. Complex default values prevents this. Record type version will use a The justifications at #2680 (comment) are fine... I didn't consider the parametrized type's case much. So I guess I'm fine with the record version. But we do need a way to indicate that the record type is erased though; enough newcomers trip over "record type not found" already |
After taking a look at
There are two conflating issues trying to be solved at once, but they are very different:
Would it be possible to change the underlying representation of records to JS objects first (like it's being proposed in #2639), and then (or in parallel) figure out the helpers generation? The fact that the type is being erased has quite some consequences. Not only for the initial confusion in the short term that this proposal is trying to address, but also for the "syntactic losses" that are imposed on any Reason / OCaml code that interacts with these functions in the mid-long term: it will be forced to interact through functions. The other question is about immutability. The setters in For my case at hand (using Reason records to replace ImmutableJS records) it would be enough with generating immutable setters & getters on top of records for now. These "lenses" are already abstracting over the internal representation of the data, so the structure the record is being compiled to internally becomes a non-issue. Using arrays would be fine, as they could be accessed from JS through the functions. |
I just realized Aren't |
I'd like records to compile to objects too, but we shouldn't do that first. We'd want these helpers generated anyway, so record-as-object shouldn't block this. When/if we do compile records to objects, this feature wouldn't break anyway (the generated type is abstract). The record type removal makes sense (but yes, it's confusing; so we should find way to clarify this). We don't want you to directly create the record type. It's just reusing the syntax for its convenience and type checking. Think Swift structs and their init function, I guess. The whole point is that you'd create/access this one using a backend-agnostic data structure.
|
Thanks @chenglou. I think I understand better the difference now.
imo, that's even better. One can always opt-in to have that code added to the output by adding |
hi @jchavarri for such type, it is quite trivial to have a functional update: let udpate this ?(x= t |. x) ?(y= t |. y) () =
t ~x ~y It is not derived currently for some reasons: a) it is not as optimized as hand written code b) it bloat the code size for people who don't rely on it, our current solution is very clean, no extra code generated |
ICYMI, the deriving works for mutual recursive types |
Postmortem: the record declaration is working out fine after a few hundred codemods |
Here's an overview of
bs.deriving abstract
currently:This generates:
t
let foo: (~high: int, ~low: option(int)=?, unit) => t
high
,low
highSet
, highLow`high(s)
might compile tos["aria-high"]
.The goal is that we get some nice helpers, but also that it can generate platform-agnostic code. E.g. for JS backend, we can compile that abstract type to a JS object.
The other option is to start with a creator function:
And generate the same helpers. This one has some advantages:
low: foo
you wouldn't know whetherfoo
isoption(int)
and accidentally makelow
non-optional.The drawback is that you for mutable field you'd need a new annotation.
I feel that the creation-based option might make more sense, but I'm not too sure.
The text was updated successfully, but these errors were encountered: