Can someone explain why this record field assignment works?

In ReScript docs there is an interesting example in Records section that is roughly equal to following example. Is there an easy explanation for why this works even if age is not directly inside the School but just a field in record:

module School = {
  type person = {age: int, name: string}
}
// This is the normal way
let me: School.person = {age: 20, name: "Me"}

// But how does School.age work here?
let you = {School.age: 30, name: "You"}

Playground link

1 Like

When you define a record like let a = {b: 1, c: 2} the compiler infers the type based on the field names. In this example, it starts by looking for a record type with the b field.

Field names are namespaced to their modules. The compiler looks inside the current module (and any opened modules) by default. By adding the module name to a field, that tells the compiler to look in that module instead.

Variants work the same way:

module M = {
  type t = A | B
}
// both work:
let a: M.t = A
let b = M.B

Note that using the explicit type name is more robust because shadowing can make the namespace syntax ambiguous and lead to unexpected type mismatches.

module School = {
  type person = {age: int, name: string}
  type cat = {age: int, name: string}
}
// This is type School.person:
let me: School.person = {age: 20, name: "Me"}
// This is inferred as type School.cat:
let you = {School.age: 30, name: "You"}
5 Likes

Very nice explanation. Thanks!