# Trouble with polymorphic variants

**URL:** <https://discuss.ocaml.org/t/trouble-with-polymorphic-variants/12511>\
**Category:** Learning\
**Created:** [June 30, 2023, 2:50am UTC](https://discuss.ocaml.org/t/trouble-with-polymorphic-variants/12511 "2023-06-30T02:50:54Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![Tom\_H](https://avatars.discourse-cdn.com/v4/letter/t/5e9695/32.png) [@Tom\_H](https://discuss.ocaml.org/u/Tom_H)\
**Post date:** [June 30, 2023, 2:50am UTC](https://discuss.ocaml.org/t/trouble-with-polymorphic-variants/12511/1 "2023-06-30T02:50:54Z")

</div>

Hey, I am declaring two types and one is the subset of the other. Snippet looks like

```auto
type dtype =
  [ `Int
  | `Bool
  | `Void
  | `NULL
  | `Pointer of dtype
  | `Array of dtype
  | `Struct of Symbol.t
  ]
let rec pp_dtype = function
    | `Int -> "int"
    | `Bool -> "bool"
    | `Void -> "void"
    | `Pointer ptr -> "*" ^ pp_dtype ptr
    | `Array arr -> pp_dtype arr ^ "[]"
    | `NULL -> "NULL"
    | `Struct s -> "struct " ^ Symbol.name s
  ;;

```

and parameter’s data type is the subset of dtype. It is a version without `struct` type.

```auto
type param =
  { t : [`Int | `Bool | `Void | `NULL | `Pointer of dtype | `Array of dtype]
  ; i : Symbol.t
  }

```

Since `param.t` is a subset of `dtype`, it should be okay to `pp_dtype param.t`. However, the error pops

```auto
This expression has type
  [`Array of dtype | `Bool | `Int | `NULL | `Pointer of dtype | `Void]
but an expression was expected of type
  [< `Array of 'a | `Bool | `Int | `NULL | `Pointer of 'a | `Void > `Void]
  as 'a
Type
  dtype =
    [ `Array of dtype
    | `Bool
    | `Int
    | `NULL
    | `Pointer of dtype
    | `Struct of Symbol.t
    | `Void ]
is not compatible with type
  [< `Array of 'a | `Bool | `Int | `NULL | `Pointer of 'a | `Void > `Void]
  as 'a 
Types for tag `Struct are incompatible

```

Is there anything I am missing 😕 ?

---

<div class="post-metadata">

**Author:** ![Tom\_H](https://avatars.discourse-cdn.com/v4/letter/t/5e9695/32.png) [@Tom\_H](https://discuss.ocaml.org/u/Tom_H)\
**Post date:** [June 30, 2023, 3:31am UTC](https://discuss.ocaml.org/t/trouble-with-polymorphic-variants/12511/2 "2023-06-30T03:31:07Z")

</div>

Oh, I figured it out. We need to explicitly indicate that `param.t` is a subset of `dtype`

```auto
pp_dtype (param.t :> dtype)

```

Bravo!

---

<div class="post-metadata">

**Author:** ![conroj](https://avatars.discourse-cdn.com/v4/letter/c/7c8e57/32.png) [@conroj](https://discuss.ocaml.org/u/conroj)\
**Post date:** [June 30, 2023, 8:03pm UTC](https://discuss.ocaml.org/t/trouble-with-polymorphic-variants/12511/3 "2023-06-30T20:03:57Z")

</div>

To spare your library users the work of figuring this out themselves and applying a coercion before every call, you can also annotate pp\_dtype with a signature that allows arguments to be subtypes of dtype, not just instances of dtype itself:

```auto
let rec pp_dtype: 'a. ([< dtype] as 'a) -> string = function
   | `Int -> ...

```

There are two special function syntax features at work here.  
`'a.` means “for every type a”. Sometimes the compiler infers a more specific type than you intend, and this says that the function definition must be general enough to support all types matching the type constraint `(... as 'a)`, which here is dtype and all of its subtypes.

Polymorphic variants are powerful but their their treatment by the compiler is subtle. Often explicit function types help ensure that you get the behavior you intend.

---

<div class="post-metadata">

**Author:** ![yawaramin](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/yawaramin/32/3384_2.png) [@yawaramin](https://discuss.ocaml.org/u/yawaramin)\
**Post date:** [June 30, 2023, 11:51pm UTC](https://discuss.ocaml.org/t/trouble-with-polymorphic-variants/12511/4 "2023-06-30T23:51:25Z")

</div>

You can also make the `t` field compatible as a subtype of `dtype`:

```auto
type param =
  { t :
      'a.
      ([< `Int | `Bool | `Void | `NULL | `Pointer of dtype | `Array of dtype]
       as
       'a);
    i : Symbol.t
  }

```

---

<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 3, 2023, 9:17am UTC](https://discuss.ocaml.org/t/trouble-with-polymorphic-variants/12511/5 "2023-07-03T09:17:15Z")

</div>

Since the error message was confusing (the error was that there is no tag ``Struct` in the second type, not that the argument type was mismatched), I decided to [fix it](https://github.com/ocaml/ocaml/pull/12347) . @Tom_H , do you want to be credited as reporter for the issue?

---

<div class="post-metadata">

**Author:** ![Tom\_H](https://avatars.discourse-cdn.com/v4/letter/t/5e9695/32.png) [@Tom\_H](https://discuss.ocaml.org/u/Tom_H)\
**Post date:** [July 6, 2023, 12:53am UTC](https://discuss.ocaml.org/t/trouble-with-polymorphic-variants/12511/6 "2023-07-06T00:53:06Z")

</div>

Sorry for the late reply… I was out town last week. I found that has already merged, is there anything I can do?

BTW, your PR is very comprehensive and concise, thank you for fixing!

---

<div class="post-metadata">

**Author:** ![Tom\_H](https://avatars.discourse-cdn.com/v4/letter/t/5e9695/32.png) [@Tom\_H](https://discuss.ocaml.org/u/Tom_H)\
**Post date:** [July 6, 2023, 1:05am UTC](https://discuss.ocaml.org/t/trouble-with-polymorphic-variants/12511/7 "2023-07-06T01:05:18Z")

</div>

Thank you for your suggestion! This constraint looks more intuitive to me.

Using `param.t :> dtype` is like `param.t` is a super set of `dtype` (because the symbol greater), and I have no idea why to use this notation.

> `'a.` means “for every type a”.

I use `'a` to indicate any type, but I find a subtle difference where you are using `'a.` with an extra dot. Is this dot going to indicate the constraint for `'a`?

---

<div class="post-metadata">

**Author:** ![Tom\_H](https://avatars.discourse-cdn.com/v4/letter/t/5e9695/32.png) [@Tom\_H](https://discuss.ocaml.org/u/Tom_H)\
**Post date:** [July 6, 2023, 1:10am UTC](https://discuss.ocaml.org/t/trouble-with-polymorphic-variants/12511/8 "2023-07-06T01:10:46Z")

</div>

I didn’t realize I can also add constraint in the type, not just function signature. Thank you for your idea 😀 !

---

<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 6, 2023, 9:14am UTC](https://discuss.ocaml.org/t/trouble-with-polymorphic-variants/12511/9 "2023-07-06T09:14:38Z")

</div>

> [@Tom\_H](#):
>
> is there anything I can do?

If you wish to be mentioned as the issue reporter, just tell me under which name: updating the changelog can be easily done, and this is really the kind of issue where consciously discovering the issue is half of the work.
