A module value that we can't create everywhere

Hi ! I’m wondering how can i forbid the creation of a module value implementing a certain module type ?

Lets say i have this module :

module type Admin = sig end

And an another module B which contain a function which take an Admin module in argument. I want that an Admin module can only be created inside the B module

Is this even possible ?

If you describe a module type, then any module which has access to this description can implement modules satisfying the description.
But just like you can export a type as abstract and prevent users from creating new values of this type, you can export a module type as abstract and prevent other modules from actually creating new implementations.
Here is a concrete example:

(* lib.ml *)

(* Concrete definition *)
module type Admin = sig end

module B = struct
  ...
  (* The signature of Admin is available *)
  module Admin1 : Admin = struct end
end

(* lib.mli *)
(* Abstract type: impossible to instantiate from outside *)
module type Admin

module B : sig
  (* Can still export existing implementations *)
  module Admin1 : Admin
end

Note that if you want to allow B to instantiate Admin but forbid other modules at the same level as B from doing the same, you will have to move the declaration of the module type Admin inside B.
In particular, if you want B to be in its own .ml file and restrict other files from instantiating the Admin type then you need to either move Admin inside B or add an extra wrapper around both B and the module that defines Admin that makes Admin abstract.

7 Likes