◄ WORLD V · SONNY 5DART 257 · a helldive at the net

THE ROW POLYMORPHISM work on any record that has these fields — and whatever else

Row polymorphism types functions over records by the fields they need, leaving the rest abstract: getX : {x : Int | r} → Int accepts any record with an x field, whatever the row variable r holds besides. It gives the flexibility of structural subtyping while keeping full type inference — the “and whatever else” is a real type variable, not a subtype relation. Records become extensible: add a field, and the row grows; a function that ignored it still type-checks. It is the principled way to type “duck typing.”

THE TECHNIQUE {x : Int | r}: fixed fields + a polymorphic row variable r

A record {a, b} extended to {a, b, c} — the row grew. The demo accesses a field of the extended record, which a row-polymorphic function handles uniformly: live demo


HISTORY & CREDIT Wand 1987 · Rémy 1989

“To be flexible about record shape you need subtyping.” — row polymorphism gets the same flexibility with a plain type variable, so inference stays complete. “Has field x and whatever else” is quantification, not subsumption. cited

1987 · Mitchell Wand — type inference for records with row variables.
1989 · Didier Rémy — a clean account of extensible records and rows.
now · PureScript records, OCaml objects/polymorphic variants, Elm, scoped labels (Leijen).

The row variable is the “whatever else” made into a type. Flexibility without subtyping means inference stays decidable — you never solve a subtyping constraint, only unify a row. Wand 1987

RECOMMEND FOR I-13 extended-record field access, computed

On the canonical compiler, extending {a,b} to {a,b,c} and reading field c (index 2) gives 30 — a row-polymorphic accessor handles the wider record unchanged:

$ i13 run t_row.i13 # access field 2 of the row-extended record extended = 30 -- {a=10, b=20, c=30}; the accessor ignores the extra row
Recommend: i13 models a record as an array and accesses fields by index (the demo reads index 2 = 30), so it has records' runtime shape and can “extend” one by appending. What it lacks is the row variable — the type-level “this works for any record that has field x, and whatever else.” Without types there is nothing to be polymorphic over: every array is just an array. Row polymorphism's whole value (flexible shape with complete inference) presupposes the type layer i13's ledger sets aside.