# Why are multiple fields of polymorphic variants not flattened?

**URL:** <https://discuss.ocaml.org/t/why-are-multiple-fields-of-polymorphic-variants-not-flattened/7899>\
**Category:** Learning\
**Created:** [May 23, 2021, 5:36am UTC](https://discuss.ocaml.org/t/why-are-multiple-fields-of-polymorphic-variants-not-flattened/7899 "2021-05-23T05:36:07Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![StrongerXi](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/strongerxi/32/2490_2.png) [@StrongerXi](https://discuss.ocaml.org/u/StrongerXi)\
**Post date:** [May 23, 2021, 5:36am UTC](https://discuss.ocaml.org/t/why-are-multiple-fields-of-polymorphic-variants-not-flattened/7899/1 "2021-05-23T05:36:07Z")

</div>

A quote from Chapter 20 (on memory representation of values) of “Real World OCaml”:

> polymorphic variants must adopt a more flexible uniform memory representation, since they may be reused in a different context across compilation units.

Also a quote from [this website](https://www.seas.upenn.edu/~cis120/archive/14sp/ocaml-3.12-manual/manual032.html):

> Unlike constructed values, polymorphic variant values taking several arguments are not flattened. That is, ‘VConstr( _v_ , _v’_ ) is represented by a block of size 2, whose field number 1 contains the representation of the pair ( _v_ , _v’_ ), rather than a block of size 3 containing _v_ and _v’_ in fields 1 and 2.

I don’t quite understand why this must be the case. Could anyone offer an example of what might go wrong if polymorphic variants always “inline” its fields into its block?

---

<div class="post-metadata">

**Author:** ![silene](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/silene/32/2707_2.png) [@silene](https://discuss.ocaml.org/u/silene)\
**Post date:** [May 23, 2021, 7:29am UTC](https://discuss.ocaml.org/t/why-are-multiple-fields-of-polymorphic-variants-not-flattened/7899/2 "2021-05-23T07:29:24Z")

</div>

The syntax of polymorphic variants is ambiguous. When you write ` `Foo (0,1)`, the compiler has no way to know whether you are talking about a constructor that takes two integer arguments or a constructor that takes a single pair argument. The compiler would need to perform a global analysis of all the compilation units to detect whether it can be the latter. Since it does not, it has to assume the worst, which leads to the inefficient memory representation.

---

<div class="post-metadata">

**Author:** ![hyphenrf](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/hyphenrf/32/2733_2.png) [@hyphenrf](https://discuss.ocaml.org/u/hyphenrf)\
**Post date:** [May 23, 2021, 10:31am UTC](https://discuss.ocaml.org/t/why-are-multiple-fields-of-polymorphic-variants-not-flattened/7899/3 "2021-05-23T10:31:53Z")

</div>

> [@silene](#):
>
> The syntax of polymorphic variants is ambiguous.

I don’t get this.  
Isn’t ``Foo(1,2)` and `Foo(1,2)` (syntactically) on the same level of ambiguity if any?

---

<div class="post-metadata">

**Author:** ![silene](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/silene/32/2707_2.png) [@silene](https://discuss.ocaml.org/u/silene)\
**Post date:** [May 23, 2021, 11:12am UTC](https://discuss.ocaml.org/t/why-are-multiple-fields-of-polymorphic-variants-not-flattened/7899/4 "2021-05-23T11:12:05Z")

</div>

> [@hyphenrf](#):
>
> Isn’t ` `Foo(1,2)` and `Foo(1,2)` (syntactically) on the same level of ambiguity if any?

For normal constructors, the mandatory type definition makes it possible to disambiguate. For polymorphic constructors, there is no such thing.

```auto
# `Foo (1,2);;
- : [> `Foo of int * int] = `Foo (1, 2)
# Foo (1,2);;
Error: Unbound constructor Foo

```

---

<div class="post-metadata">

**Author:** ![StrongerXi](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/strongerxi/32/2490_2.png) [@StrongerXi](https://discuss.ocaml.org/u/StrongerXi)\
**Post date:** [May 23, 2021, 1:21pm UTC](https://discuss.ocaml.org/t/why-are-multiple-fields-of-polymorphic-variants-not-flattened/7899/5 "2021-05-23T13:21:50Z")

</div>

This makes sense, although I’m surprised that a grammar choice leads to inefficient backend code…  
Why didn’t the dev team choose a different syntax for instantiating a polymorphic variant? Was there any discussion on this?

---

<div class="post-metadata">

**Author:** ![octachron](https://avatars.discourse-cdn.com/v4/letter/o/49beb7/32.png) [@octachron](https://discuss.ocaml.org/u/octachron)\
**Post date:** [May 23, 2021, 3:33pm UTC](https://discuss.ocaml.org/t/why-are-multiple-fields-of-polymorphic-variants-not-flattened/7899/6 "2021-05-23T15:33:16Z")

</div>

The issue cuts deeper than just the syntax. Using unboxed tuples for polymorphic variant arguments would also expose them indirectly to the type system. For instance, the type ` [`Foo of #('a * 'b)]` is not compatible with `[`Foo of 'c]`. In the case of normal constructor, those unboxed types are mostly kept under wraps, and only manifest themself when pattern matching using the wrong arity:

```ocaml
type unboxed = Foo of int * int
let error (Foo x) = x
type boxed = Foo of (int * int)
let fine (Foo x) = x

```

---

<div class="post-metadata">

**Author:** ![StrongerXi](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/strongerxi/32/2490_2.png) [@StrongerXi](https://discuss.ocaml.org/u/StrongerXi)\
**Post date:** [May 23, 2021, 8:57pm UTC](https://discuss.ocaml.org/t/why-are-multiple-fields-of-polymorphic-variants-not-flattened/7899/7 "2021-05-23T20:57:22Z")

</div>

Hmm I think I understood your point, but wouldn’t the following grammar eliminate the ambiguity and leaves the type system intact? (vertical bar is picked arbitrarily)

```auto
`Foo |e1, e2, ..., en| (* n >= 0 *)

```

So we have either one of following:

```auto
`Foo |(1, 2)|
`Foo |1, 2|

```

It doesn’t look like regular variants anymore, but it’s semantically different from those anyway, and there seems to be no backward compatibility issue if we introduced it this way (I’m just trying to understand the development process behind this, not proposing a change at all).

---

<div class="post-metadata">

**Author:** ![octachron](https://avatars.discourse-cdn.com/v4/letter/o/49beb7/32.png) [@octachron](https://discuss.ocaml.org/u/octachron)\
**Post date:** [May 23, 2021, 9:35pm UTC](https://discuss.ocaml.org/t/why-are-multiple-fields-of-polymorphic-variants-not-flattened/7899/8 "2021-05-23T21:35:59Z")

</div>

The type system needs to handle the situation when different part of the code base try to use the same polymorphic variant constructor with different arities. Consider for instance,

```ocaml
let both f x =
  let `Foo a = x in
  let `Foo |b,c| = x in
  f a + b + c

```

The type of `both` is something like: `('a -> int) -> [< `Foo of #(int * int) & 'a] -> int`, where `'a` and `#(int *int)` have different kinds and cannot be unified.

---

<div class="post-metadata">

**Author:** ![StrongerXi](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/strongerxi/32/2490_2.png) [@StrongerXi](https://discuss.ocaml.org/u/StrongerXi)\
**Post date:** [May 24, 2021, 8:03pm UTC](https://discuss.ocaml.org/t/why-are-multiple-fields-of-polymorphic-variants-not-flattened/7899/9 "2021-05-24T20:03:58Z")

</div>

> different part of the code base try to use the same polymorphic variant constructor with different arities

This is what I was missing. Thank you so much!

---

<div class="post-metadata">

**Author:** ![Levi\_Roth](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/levi_roth/32/2268_2.png) [@Levi\_Roth](https://discuss.ocaml.org/u/Levi_Roth)\
**Post date:** [July 14, 2023, 11:03am UTC](https://discuss.ocaml.org/t/why-are-multiple-fields-of-polymorphic-variants-not-flattened/7899/10 "2023-07-14T11:03:39Z")

</div>

I think I’m still confused. If the kinds can’t be unified, why can’t that just be a compile-time error at the point where you try to unify them? Is the issue here one of soundness, or is it “just” that it would take more work on the type system to be able to handle cases like this?

---

<div class="post-metadata">

**Author:** ![octachron](https://avatars.discourse-cdn.com/v4/letter/o/49beb7/32.png) [@octachron](https://discuss.ocaml.org/u/octachron)\
**Post date:** [July 17, 2023, 8:10am UTC](https://discuss.ocaml.org/t/why-are-multiple-fields-of-polymorphic-variants-not-flattened/7899/11 "2023-07-17T08:10:34Z")

</div>

OCaml doesn’t have a layout kind system (I was using the notation from the [unboxed types RFC](https://github.com/ocaml/RFCs/pull/34)) that would allow to express the issue as a layout mismatch. Thus the language doesn’t allow the mismatch to arise by choosing the default layout kind which is used for all first-class types.

Note that echoes of other layouts do appear currently in OCaml, but only in second-class objects like inline records, elements of an unboxed array, or argument of a n-ary constructor (with n\>1).
