Ocaml provides three kinds of encapsulation for types:
Everything works as described but reading anything from a private tuple is impossible.
For example, the following example with a record type works fine:
module Private : sig
type t = private { a : int }
val make : int -> t
end = struct
type t = { a : int }
let make a = { a }
end
let x = Private.make 5
let a = x.a
let Private.{ a = value } = x
But it is impossible to extract any value in the relevant example with a tuple.
module Private : sig
type t = private int * int
val make : int -> int -> t
end = struct
type t = int * int
let make a b = a, b
end
let x = Private.make 5 6
let Private.(a, b) = x
Compiler gives me the error for the last line of code:
Error: This expression has type Private.t but an expression was expected of type 'a * 'b
I tried many different failed attempts of reading from private tuples. And my result is that there is no way to do that.
Is it possible to do so? If it is not, does it destroy the conception of private types or do I miss something in my understanding?
Note
I have checked that it is impossible to execute private functions too.
module Private : sig
type t = private int -> int
val make : int -> int -> t
end = struct
type t = int -> int
let make a b = fun x -> if x = b then b else 0
end
let f = Private.make 5 6
let res = f 5
Error: This expression has type Private.t This is not a function; it cannot be applied.
tl;dr: this will work:
let (a, b) = (x :> int * int)
There's a difference between private record and variant types (which are nominal types), and private type abbreviations. And private row types, but let's not go there.
Private record and variant types can be destructured, private type abbreviations cannot. They can be coerced to their underlying type however, which is what the above does.
You can perhaps get an intuition for why this is if you consider the case of a single private int
. The purpose there is often to make sure you can't freely mix it with plain int
s. For example:
module Id : sig
type t = private int
val make : int -> t
end = struct
type t = int
let make a = a
end
let my_id = Id.make 42
let other_id = my_id + 3 (* This is probably not what you want *)
let x: int = (my_id :> int) + 3 (* This works, and is unambiguous *)
And since a pair of int
s is just that, it makes sense (to me at least) that it would behave the same.