Are OCaml records structurally typed or nominally typed?

I think they’re nominally typed. Consider this example:

type student_t = {
  age: int;
}

type worker_t = {
  age: int;
}

let new_worker (age: int) : worker_t = {age = age;}

let is_adult (student: student_t) : bool = student.age >= 18

I get a type error when I do:

let result = is_adult (new_worker 20)

I don’t know what you mean by “nominally”, but a record-declaration declares these new field-names. Do it again (the identical declaration), and you redeclare the field-names. The new declarations obscure (or “shadow”) the old ones. But code or data that was created using the first declaration will necessarily be incompatible with the type of the second declaration.

2 Likes

An example from Flow’s website:

Records are nominally typed, but objects are structurally typed. They are even given as the example on Structural type system - Wikipedia :slight_smile:

2 Likes

It means to be identified by its name. Java, for example, is nominally typed.

Not sure if this followup makes sense: Are OCaml modules structurally typed ?

Sort of, but probably not in the way you would expect them to be.

module type S = sig
  type t
  val x : t
end

module A = struct
  type t = int
  val x = 12
  val y = 13
end

Here, A : S holds, but using A in a spot were a S is required will result in a copy of the module being made. That copy will only contain x. I believe that the reasoning for that is that accessing a module field is frequent, so it needs to be fast, but coercing a module to a subtype only happens when you pass it to a functor, which is not too often (hopefully).

3 Likes