Records

When two record types share field names, the last defined wins unless you annotate:

11.1 Defining and creating

type person = {
  name : string;
  age : int;
  email : string option;
}

let alice = { name = "Alice"; age = 30; email = None }

11.2 Accessing fields

alice.name                     (* "Alice" *)
let { name; age; _ } = alice   (* destructuring with field punning *)
let greet { name; _ } = "Hi " ^ name

11.3 Functional update (copy with changes)

let older = { alice with age = alice.age + 1 }   (* alice is unchanged *)

11.4 Field punning when constructing

let make name age = { name; age; email = None }

11.5 Type-directed disambiguation

When two record types share field names, the last defined wins unless you annotate:

type a = { id : int }
type b = { id : int; label : string }
let get_id (x : a) = x.id
let v = ({ id = 1 } : a)
let w = M.{ id = 1 }          (* or qualify with a module path: { M.id = 1 } *)

11.6 Mutable fields

type counter = { mutable count : int }
let c = { count = 0 }
let () = c.count <- c.count + 1

11.7 Parameterised records

type 'a box = { value : 'a; label : string }
let b = { value = 42; label = "answer" }   (* int box *)