Skip to content

Record type spread and coercion blog post #681

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 6 commits into from
May 17, 2023
Merged

Conversation

zth
Copy link
Collaborator

@zth zth commented May 14, 2023

All feedback welcome.

Copy link
Member

@ryyppy ryyppy left a comment

Choose a reason for hiding this comment

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

Really nice post! Added some comments / recommendations. Feel free to ignore if not applicable.

@zth
Copy link
Collaborator Author

zth commented May 16, 2023

@ryyppy if you re-read it now with fresh eyes after the latest changes, how does it look?

@zth
Copy link
Collaborator Author

zth commented May 17, 2023

Let's add 2 short sentences to illustrate:

  • Coercing between optional and mandatory fields
  • Repeated fields are disallowed

cc @cristianoc

@ryyppy
Copy link
Member

ryyppy commented May 17, 2023

As discussed with @zth, I restructured the text a bit.

Coercing between optional and mandatory fields

I don't fully understand how this would look like. The only coercion I got to work was this:

type a = {
  name: string,
  age: option<int>,
}

type b = {
  age?: int,
  name: string,
}

let test = (v: b) => {
  Js.log(v.name)
}

let a: a = {name: "Bambi", age: Some(1)}

test((a :> b))

For me this feels quite natural, so not sure if this example yields any benefit? Or maybe I don't understand what is meant by "coercing between optional and mandatory fields".

@cristianoc
Copy link
Contributor

As discussed with @zth, I restructured the text a bit.

Coercing between optional and mandatory fields

I don't fully understand how this would look like. The only coercion I got to work was this:

type a = {
  name: string,
  age: option<int>,
}

type b = {
  age?: int,
  name: string,
}

let test = (v: b) => {
  Js.log(v.name)
}

let a: a = {name: "Bambi", age: Some(1)}

test((a :> b))

For me this feels quite natural, so not sure if this example yields any benefit? Or maybe I don't understand what is meant by "coercing between optional and mandatory fields".

That is indeed the example of converting from mandatory to optional.

@cristianoc
Copy link
Contributor

cristianoc commented May 17, 2023

"Record Type Coercion is Explicit

Records are still nominally typed, so it is not possible to pass a record a as record b without an explicit type coercion. This is crucial as it prevents accidental dependencies on shapes rather than records, ensuring predictable and more robust type checking results.
"

The explicitness of coercion is a design choice, not an implementation necessity.
We could have implemented implicit subtyping. This has not been done, as that might be "too magic".

@cristianoc
Copy link
Contributor

With current docs.

Is it possible to coerce a mandatory field of option type to an optional field?

No, it is not possible to coerce a mandatory field of an option type to an optional field in ReScript. Coercion does not allow for changing the required/optional status of fields, even if the original field is of type option.

Here's an example to illustrate this:

type a = {
  name: string,
  age: option<int>, // Mandatory field of option type
}

type b = {
  name: string,
  age?: int, // Optional field
}

let aRecord: a = {
  name: "John",
  age: Some(25), // Option field is present
}

let bRecord: b = aRecord :> b // Error: Cannot coerce 'a' to 'b'

In the above example, type a has a mandatory field age of type option<int>, while type b has an optional field age of type int. When trying to coerce aRecord of type a to bRecord of type b, a compilation error will occur because coercion cannot change the required/optional status of fields.

If you need to convert a record with a mandatory field of an option type to a record with an optional field, you will need to create a new record with the desired optional field explicitly set based on the presence or absence of the option value.

@ryyppy ryyppy merged commit b7acc4f into master May 17, 2023
@ryyppy ryyppy deleted the record-spread-coercion-post branch May 17, 2023 20:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants