> you cannot use subtype polymorphism to have a heterogeneous list of objects
You can by using an existential type parameter, which 'forgets' the types in much the same way as an upcast.
[exists p. {x:int; p}]
You can by using an existential type parameter, which 'forgets' the types in much the same way as an upcast.
[exists p. {x:int; p}]
With row typing instead of subtyping you have "row variables". That function that would receive a {x:int} is typed as "forall p. {x:int; p}". You can pass the function a {x:int, y:int} because it unifies p with {y:int}. But you cannot freely convert a {x:int, y:int} to a {x:int}, it is all based around parametric polymorphism.
This system with row variables works much better with hindley-milner type inference but it is a bit more restrictive. For example, you cannot use subtype polymorphism to have a heterogeneous list of objects. If you have a function that receieves a "forall p. [{x:int; p}]" you can have a list of {x:int} or a list of {x:int, y:int} but every element of the list must have the same type.