Classe Tipo esempio la coercizione a firma del modulo
Domanda
Molti dei miei moduli contengono istanze di classe a livello mondiale che implementano un dato tipo di classe con due metodi, private_method
e public_method
.
Voglio MyModule.my_instance # public_method
per essere disponibile da qualsiasi luogo nel mio programma, e MyModule.my_instance # private_method
di essere disponibile solo all'interno MyModule
.
Ho tentato quanto segue:
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
Tuttavia, questo si traduce in un errore:
I valori non corrispondono:
val my_instance : private_type
non è incluso nel
val my_instance : public_type
I potrebbero scrivere la coercizione 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
Ma preferisco non raddoppiare la dimensione del codice per qualcosa di semplice come questo.
Avete qualche suggerimento sul perché questo accade, e come posso lavorare intorno ad esso?
Soluzione
Non ci sono coercizioni impliciti in OCaml. Forse vale la pena di mettere la coercizione in funtore (se si dispone di diversi moduli con queste stesse proprietà):
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)
Altri suggerimenti
Probabilmente la tecnica migliore per risolvere questo è quello di utilizzare fila privato tipi come descritto da Garrigue ( "private tipi di riga: astraendo le senza nome", si prega di guardare in su come non riesco a postare un secondo link ad esso). Questo può essere utilizzato con un'espressione esplicita tipo di oggetto:
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 un percorso dell'oggetto (che è quello che si richiede):
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 ;;