Question

Several of my modules contain global class instances that implement a given class type with two methods, private_method and public_method.

I want MyModule.my_instance # public_method to be available from anywhere in my program, and MyModule.my_instance # private_method to be available only within MyModule.

I have attempted the following:

class type public_type = object
  method public_method  : int
end ;;

class type private_type = object
  method public_method  : int
  method private_method : int
end ;;

let make_private : unit -> private_type = fun () -> object
  method public_method  = 0
  method private_method = 0
end ;;

module type MY_MODULE = sig
  val my_instance : public_type
end

module MyModule : MY_MODULE = struct
  let my_instance = make_private ()
  let _           = print_int (my_instance # private_method)
end 

However, this results in an error:

Values do not match:

val my_instance : private_type

is not included in

val my_instance : public_type

I could write the coercion manually:

module MyModule : MY_MODULE = struct
  let my_instance = make_private ()
  let _           = print_int (my_instance # private_method)

  let my_instance = (my_instance :> public_type)
end 

But I'd rather not double the code size for something as simple as this.

Do you have any suggestions on why this happens, and how I can work around it?

Was it helpful?

Solution

There are no implicit coercions in ocaml. Maybe it is worth putting coercion into functor (if you have several modules with these same properties) :

module Hide(M:sig val my_instance : private_type end) : MY_MODULE =
struct
  let my_instance = (M.my_instance :> public_type)
end

module MyModule = Hide (struct
  let my_instance = make_private ()
  let _           = print_int (my_instance # private_method)
end)

OTHER TIPS

Probably the best technique to solve this is to use private row types as described by Garrigue ("Private Row Types: Abstracting the Unnamed"; please look it up as I can't post a second link to it). This can be used with an explicit object type expression:

module type MY_MODULE2 = sig
  type t = private < public_method : int; ..>
  val my_instance : t
end ;;

module MyModule2 : MY_MODULE2 = struct
  type t = private_type
  let my_instance = make_private ()
  let _           = print_int (my_instance # private_method)
end  ;;

or with an object path (which is what you require):

module type MY_MODULE3 = sig
  type t = private #public_type
  val my_instance : t
end ;;

module MyModule3 : MY_MODULE3 = struct
  type t = private_type
  let my_instance = make_private ()
  let _           = print_int (my_instance # private_method)
end  ;;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top