-
Notifications
You must be signed in to change notification settings - Fork 465
Proposal to provide cleaner representation for poly variants #4295
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 a cool idea, but perhaps as an optional extension? I really like how poly variants are represented in JS at the moment, at a certain size binary tree lookup will be more efficient than a switch statement (although it would be nice if the numbers used were smaller to reduce bundle size). What about tuples though?
|
There's also a question of whether this could be implemented in a way that would allow modeling of discriminated/tagged unions like we've seen from @ryyppy https://dev.to/ryyppy/tagged-unions-and-reasonml-variants-4428 (and @zth has mentioned this idea as well) It might be out of scope for this idea, but it also might be a nice thing to consider to see if it's capable of being succinctly represented. |
So in #3801 Bob is proposing to encode ordinary variants like |
In that case, you'd presumably want to do the equivalent of |
Polymorphic variants also have a numeric tag today, it's just a long generated number. That might make it quite difficult to use strings for the tag field. |
I am thinking to make it like this |
@bobzhang Is that also for flat polymorphic variants? To model a lot of the enums that underlying JavaScript uses strings for, it'd be great to be able to compile out to strings (especially if it also works with
Have |
For interop I think what would be really nice is:
Let me expand a bit on that last point. As can be seen in the article from @ryyppy and from looking at how most ASTs (and unions overall) are represented in TS/JS, there's a whole host tools that use a structure like this for unions in TypeScript/Flow: interface VariableNode {
kind: "VariableNode"; // String literal
value: string; // ...any props specific to this particular node is just put right on the node itself
name: string;
}
interface ArgumentNode {
kind: "ArgumentNode"; // String literal
argumentName: string;
}
type ast = VariableNode | ArgumentNode; If we could get BuckleScript to somehow natively understand that type of structure without needing conversion, that would be very powerful. Some pseudo code: type ast [@bs.discriminator "kind"] = VariableNode({ value: string, name: string }) | ArgumentNode({ argumentName: string }); This would mean that we could bind to a whole host of ASTs in JS with zero runtime costs for the developer (Babel, TypeScript, GraphQL are just a few I've seen that uses that structure, but I think using Again, this is just what I think would be great for interop, no other cases taken into consideration here ;) |
@zth yeah, similar to #3801 (comment) . Fwiw I think for polymorphic variants (with payloads) a For polyvariants a |
@yawaramin I can see a use case for both forms: type t = [ `foo | `bar of int ]
let a = `foo
let b = `bar 123
var a = "foo"
var b = { type: "bar", value: 123 }
var a = { type: "foo" }
var b = { type: "bar", value: 123 } I don't think a compiler flag would fix all the issues, because you might want to mix and match styles. And I can also see there being a big split on this issue since there's a desire for both styles. The thing is though that, unlike #1, the #2 form can be achieved with some reworking of the code: type t = [ `foo of unit | `bar of 123 ]
let a = `foo ()
let b = `bar 123 compiling to: var a = { type: "foo" }
var b = { type: "bar", value: 123 } Which would make the #1 version preferable in my opinion, since #2 is still achievable and not unpleasant to work with. |
@Risto-Stevcev oh I didn't mean a compile flag for the simple string vs uniform shape outputs, I meant for the name of the |
As an intermediate step, in next version , for non-nullable poly-variant |
Ah so you're keeping the hash for all, nice. At least my concern won't be a problem, even if it's still less than ideal. I can guess how hard it would be to not have the hash available at runtime. |
so for non-debug mode it would be
for debug mode, it is
Note that the current encoding is better but still not ideal, we will stop here and revisit it when we upgrade the upstream compiler |
One of the pain points of using bucklescript over typescript are the type representations when compiled to js. Having the unboxed option type turns out to be extremely useful both for targeting js (ie: writing libs in bucklescript that can be used in js projects) and ingesting js libs.
The proposal here is provide a cleaner js representation for poly variants or both poly and regular variants. For example:
becomes
and
becomes
This would make it much easier to interact with js libs, making something like
[@bs.unwrap]
unnecessary. It would also make it easier to write libraries that can be used as both a bucklescript library and a plain js library, because the representations would compile to clean js code without the need for a compatibility module for js withjsConverter
s that could potentially lead to a really large bundle size.The text was updated successfully, but these errors were encountered: