## Row Polymorphism Isn't Subtyping

I’ve been working on Roy’s new type system which uses a concept called
*row variables*. I’ve also been thinking about TypeScript’s
unsound variance issues with
its implementation of structural subtyping. That lead to an
interesting discussion
on Twitter about row polymorphism compared to structural subtyping.

Both are trying to type code like the following:

```
let f x = x.a + x.b
f {a: 1, b: 2, c: 100}
```

Also known as static duck typing.

Structural subtyping of course uses *subtyping* to achieve the
above. Subtyping involves the rule of subsumption:

In English: if we have a term `t`

in our environment of type `T1`

and
`T1`

is a subtype of `T2`

, then that term also has type `T2`

.

In structural subtyping, a wider record type is *subsumed* by a
narrower one. Due to contravariance of function inputs, we can supply
any subsumed record to `f`

:

`f :: {a: Number, b: Number} -> Number`

Row polymorphism instead achieves the original code is by allowing records to have a special polymorphic variable:

The rho (ρ) represents a variable which can be instantiated to extra
fields. That means the type of `f`

is:

`f :: {a: Number, b: Number | ρ} -> Number`

And when we apply `f`

, `ρ`

is *instantiated* to contain the extra
field, `c: Number`

.

So now to answer the question, is row polymorphism a form of
subtyping? No, because of the *instantiation* of the row variable, we
can’t derive the rule of subsumption. It would need a separate
instantiation step defined and that means there is no subtyping
relationship.

Here’s a simple example of where the row instantiation can cause differences:

```
let f x = x with {sum: x.a + x.b}
let answer = f {a: 1, b: 2, c: 100}
```

With structural subtyping, the type is upcast to what `f`

needs and
we get back:

`answer :: {a: Number, b: Number, sum: Number}`

But with row polymorphism, the row variable `ρ`

gets *instantiated* to
contain the `c`

field:

`answer :: {a: Number, b: Number, c: Number, sum: Number}`

Great. Row polymorphism isn’t subtyping. Who cares? Well, subtyping and type inference just don’t mix. Doing type inference with row polymorphic records is much easier. There’s still undecidability problems but if you’re writing a language with type inference and want records, you should take a look at row variables.