# Difference between row-polymorpism and bounded polymorpishm?

I recently came across this blog post by Brian McKenna explaining row polymorphism. This seemed like a wonderful idea to me, but then I realized it smells an awful lot like bounded parametric polymorphism:

With row-polymorphism:

sum: {x: int, y: int | rho} -> int
function sum r = r.x + r.y


With bounded parametric polymorphism:

sum: forall a <: {x: int, y: int}. a -> int
function sum r = r.x + r.y


Can someone clarify the differences to polymorphism between these two approaches?

• Have you tried typing let f x = x with {sum: x.a + x.b} with both? If I understand correctly, row-polymorphism will allow you to keep whatever extra fields are in the x but bounded parametric polymorphism will not because you'd want to say that is has type forall a <: {x: int, y: int}. a -> a_with_a_new_field_sum and I don't think you can express a_with_a_new_field_sum. Mar 8 '17 at 10:38
• Hm, I think it depends on that exact semantics of the with construct. Since that wasn't laid out in the article, I tried to avoid it, because it confuses matters. Mar 8 '17 at 14:51
• Well (I think that) the expressiveness of row polymorphism comes from the fact that you get a name for "and a bunch of other attributes". So if you don't use the type variable representing that bunch of other attributes in the typing of your function, then you probably don't really need row polymorphism. You could also have some forget operator that takes a record and removes one of its fields. Then, to type fun r -> forget x of r, you'd probably also need row polymorphism. Mar 8 '17 at 15:07
• Without more detail about the systems, I'd say they roughly are equivalent except, of course, bounded polymorphism is more general. Usually row typing also implies some type level operations on rows such as row union or row restriction. I say similar sorts of things in this answer. Mar 9 '17 at 4:58

• In row polymorphism, you've bound $\rho$ to a name, so you can use it elsewhere. For example, forall rho . rho -> {x : int | rho} is expressible with row polymorphism, but not purely using bounded polymorphism. Likewise, you can even express field deletion this way: forall rho .{x : int | rho} -> rho is a perfectly valid row-polymorphic type, but subtyping doesn't really have a way of expressing this.
• Bounded subtyping uses, well, subtyping. So with row polymorphism, you can't give x : {x : int, y : int} as argument to a function of type {x : int} ->int. But most systems with bounded subtyping would have non-polymorphic subtyping too, that would allow this, since most systems have {x : int} <: {x : int, y : int}.