开发者

Class instance type coercion in module signature

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?


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)


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  ;;
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜