Tipo de instancia de clase coerción en la firma del módulo
Pregunta
Varios de mis módulos contienen instancias de clase mundial que implementan un tipo de clase dada con dos métodos, private_method
y public_method
.
Quiero MyModule.my_instance # public_method
esté disponible desde cualquier lugar en mi programa, y ??MyModule.my_instance # private_method
a estar disponible sólo dentro de MyModule
.
He intentado lo siguiente:
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
Sin embargo, esto resulta en un error:
Los valores no coinciden:
val my_instance : private_type
no está incluido en
val my_instance : public_type
podría escribir la coerción manualmente:
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
Pero prefiero no duplicar el tamaño del código para algo tan simple como esto.
¿Tiene alguna sugerencia sobre qué sucede esto, y cómo puede trabajar alrededor de ella?
Solución
No hay coacciones implícitas en ocaml. Tal vez vale la pena poner en la coacción funtor (si dispone de varios módulos con estas mismas propiedades):
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)
Otros consejos
Probablemente la mejor técnica para resolver esto es utilizar fila privada tipos según lo descrito por Garrigue ( "tipos de fila privadas: abstracción de los sin nombre", por favor, ven hacia arriba ya que no puedo publicar un segundo enlace a ella). Esto se puede utilizar con una expresión tipo de objeto explícito:
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 ;;
o con una ruta de objeto (que es lo que necesita):
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 ;;