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?

È stato utile?

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  ;;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top