I’m having a lot of trouble figuring out what private type abbreviations are good for. Private type abbreviations arrived as a new feature in OCaml 3.11, but I still don’t know where I would want to use them. Here’s a simple example of a private type abbreviation. First, let’s write down a trivial module that has an int type and a couple of trivial helper functions:

module Int = struct
  type t = int
  let of_int x = x
  let to_int x = x

That’s not very interesting on its own, but we can apply a signature to make t private:

module Priv : sig =
  type t = private int
  val of_int : int -> t
  val to_int : t -> int
end = Int

And you can do something similar to make t abstract.

module Abstr : sig =
  type t
  val of_int : int -> t
  val to_int : t -> int
end = Int

The question is, when would one prefer Priv to Abstr?

Now, I’m aware that there are some optimization differences. For example, the following code uses the slower compare_val to compare its ints:

Abstr.of_int 3 > Abstr.of_int 4

whereas this code uses a more efficient specialized-to-int comparator.

Priv.of_int 3 > Priv.of_int 4

But the difference here is really a weird compiler optimization difference. There’s no fundamental reason that the abstract version shouldn’t be able to do the same optimization as the private one. Semantically, there’s nothing interesting going on here.

There is one thing that I know how to do with a private type that I can’t do with an abstract type: coercions. In particular, this code compiles:

let five =
  let x = Priv.of_int 4 in
  (x :> int) + 1

whereas the same code with the abstract type fails. But that doesn’t seem all that interesting, since I can write the following essentially equivalent code:

let five =
  let x = Abstr.of_int 4 in
  Abstr.to_int x + 1

I had some other theories about what one could do with private types, but none of them seemed to pan out. For instance, the following all fail to compile:

let p = Priv.of_int 4

let _ = p + 1

let _ =
  match p with
  | 0 -> true
  | _ -> false

let _ =
  let f x = (x :> int) + 1 in
  f p

So is there some deeper purpose here that I’m missing?

To be clear, ordinary private types are clearly useful, since they let you have access to pattern matching and record fields, while still giving you many of the advantages of a private type. But private type abbreviations are still pretty much a mystery to me.