lambdapower
lambdapower

Reputation: 1032

External and internal interfaces & information hiding in OCaml

When creating a library from multiple modules, I cannot find a nice way to do proper information hiding to the user of the library (external interface) while being able to access everything I need on the internal interface.

To be more specific, I have two modules (Files a.ml[i] and b.ml[i]). In A, I define some type t, thats internals I don't want to hide from the user (external interface).

module A : sig
  type t
end
module A = struct
  type t = float
end

In module B, I then want to use the secret type of A.t.

module B : sig
  create_a : float -> A.t
end
module B = struct
  create_a x = x
end

This of course does not compile, because the compilation unit of B does not know the type of A.t.

Solutions I know, but don't like:

  1. Move the function create_a to module A
  2. Copy the definition of A.t to B and cheat the type checker with some external cheat : `a -> `b = "%identity"

Is there some other way to know the type of A.t in B without leaking this information to the library's interface?

Upvotes: 5

Views: 864

Answers (1)

ivg
ivg

Reputation: 35280

As always an extra layer of indirection can solve this problem. Define a module Lib that will specify an external interface, e.g.,

module Lib : sig 
 module A : sig
   type t
   (* public interface *)
 end
 module B : sig 
    type t 
    (* public interface *)
 end = struct 
   module A = A
   module B = B
 end

If you don't want to repeat yourself and write module signatures twice, then you can define them once in a module sigs.ml:

 module Sigs = struct
   module type A = sig 
     type t
     (* public interface *)
   end

   (* alternatively, you can move it into sigs_priv.ml *)
   module type A_private = sig 
     include A
     val create_a : float -> t
   end

   ...
 end

Finally, make sure that you're not installing interfaces (the .cmi files), during your installation step, so that users can't bypass your abstraction. If your're using oasis, then it is simple: just make all your modules internal, except the module Lib, i.e., specify them with InternalModules field.

Upvotes: 7

Related Questions