Skip to content

Support union parameters #585

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

Merged
merged 1 commit into from
May 1, 2025
Merged

Support union parameters #585

merged 1 commit into from
May 1, 2025

Conversation

karlseguin
Copy link
Collaborator

There's ambiguity in mapping due to the flexible nature of JavaScript. Hopefully most types are unambiguous, like a string or a *parser.Node.

We need to "probe" each field to see if it's a possible candidate for the JS value. On a perfect match, we stop probing and set the appropriate union field. There are 2 levels of possible matches: candidate and coerce. A "candidate" match has higher precedence. This is necessary because, in JavaScript, a lot of things can be coerced to a lot of other, seemingly wrong, things.

For example, say we have this union:

a: i32,
b: bool,

Field a is a perfect match for the value 123. And field b is a coerce match (because, yes, 123 can be coerced to a boolean). So we map it to a.

Field a is a candidate match for the value 34.2, because float -> int are both "Numbers" in JavaScript. And field b is a coerce match. So we map it to a.

Both field a and field b are coerce matches for "hello". So we map it to a because it's declared first (this relies on how Zig currently works, but I don't think the ordering of type declarations is guaranteed, so that's an issue).

Copy link
Contributor

@sjorsdonkers sjorsdonkers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if it is needed to do a deep dive review.
I think we should consider moving specifically the jsValueToZig and vice-verse chain of functions to a separate file.

//
// The way we'll do this is that, if there's a direct match, we'll use it
// If there's a potential match, we'll keep looking for a direct match
// and only use the (first) potential match as a fallback.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just the first one as defined in the order of the union variants? No, type based or like an integer is rather a float than a string. I would expect JS to be highly unpredictable instead of something as straightforward as just the first. Dunno :)
I think this is going to be very hard to get exactly right in the first implementation

Copy link
Collaborator Author

@karlseguin karlseguin May 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Order is used as a tie-breaker only when no exact match is available.

if you have a union:

a: i32,
b: bool
c: f32

And you pass a true, then it'll map to b. If you pass a 1.445, it'll map to c. But if you pass "hello" which, in JavaScript, can safely be coerced to an integer, a boolean and a float, it'll pick a.

There's ambiguity in mapping due to the flexible nature of JavaScript. Hopefully
most types are unambiguous, like a string or am *parser.Node.

We need to "probe" each field to see if it's a possible candidate for the JS
value. On a perfect match, we stop probing and set the appropriate union field.
There are 2 levels of possible matches: candidate and coerce. A "candidate"
match has higher precedence. This is necessary because, in JavaScript, a lot
of things can be coerced to a lot of other, seemingly wrong, things.

For example, say we have this union:

a: i32,
b: bool,

Field `a` is a perfect match for the value 123. And field b is a coerce match
(because, yes, 123 can be coerced to a boolean). So we map it to `a`.

Field `a` is a candidate match for the value 34.2, because float -> int are both
"Numbers" in JavaScript. And field b is a coerce match. So we map it to `a`.

Both field `a` and field `b` are coerce matches for "hello". So we map it to `a`
because it's declared first (this relies on how Zig currently works, but I don't
think the ordering of type declarations is guaranteed, so that's an issue).
@karlseguin karlseguin merged commit 74eaee5 into main May 1, 2025
12 checks passed
@karlseguin karlseguin deleted the union_params branch May 1, 2025 11:20
@github-actions github-actions bot locked and limited conversation to collaborators May 1, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants