Класс экземпляра Тип принуждения в подписи модуля
Вопрос
Несколько моих модулей содержат экземпляры глобального класса, которые реализуют данный тип класса с двумя методами, private_method
и public_method
.
Я хочу MyModule.my_instance # public_method
Быть доступным из любой точки моей программы и MyModule.my_instance # private_method
быть доступным только внутри MyModule
.
Я попытался следующее:
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
Однако это приводит к ошибке:
Значения не совпадают:
val my_instance : private_type
не включен в
val my_instance : public_type
я мог Напишите принуждение вручную:
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
Но я бы предпочел не удвоить размер кода для чего-то так просто, как это.
Есть ли у вас какие-либо предложения по тому, почему это происходит, и как я могу обойти его?
Решение
В Ocaml нет неявных принуждений. Может быть, стоит поставить принуждение в функтор (если у вас есть несколько модулей с этими же свойствами):
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)
Другие советы
Вероятно, лучшая техника для решения этого является использование Личные типы строк Как описано Garrigue («Частные типы строки: абстрагирование Безмятенных»; пожалуйста, посмотрите, как я не могу опубликовать вторую ссылку на него). Это может использоваться с явным выражением типов объекта:
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 ;;
или с пути объекта (который вы требуете):
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 ;;