Coming from Javascript, I sometimes tempt to write function closure to enclose the mutable state inside a function and returns “management” funtions to manipulate them, as in the below example:
let itemContainer () =
let zone_items = Hashtbl.create 1 in
let add (key : string) (content : string) =
Hashtbl.add zone_items key content
in
let getCount () = Hashtbl.length zone_items in
(add, getCount)
Then I use add/getCount returned from the itemContainer to operate on zone_items. Now I’m wondering if this is a valid design as I can’t see much discussion in function closure in the documentation, and I know I can use functor to implement it, but it looks more heavy weighted and the pros and cons of each design is still uncleared to me. Can somebody guide me?
It’s not uncommon to do something like this for small stuff. A typical example is a generator for numbers or names where the state of the function is hidden in the closure.
As soon as you have multiple functions to access this state it’s more common to use the module system to achieve this. The module would implement an abstract type t that holds the state and functions to manipulate them. If only ever one instance of t is needed, the module could hide that as well and functions would not receive a t value.
One issue in this example (more an inconvenience really), the state is share across 2 functions. So if we want to have multiple instances of containers we need to make sure to always track pair of add/getCount correctly.
I can use functor to implement it
You don’t need functor here, there is nothing generic, the type of the key and content are fixed to string. Module will be more than enough:
module Container : sig
type t
val add : t -> string -> string -> unit
val getCount: t -> int
end = struct
type t = (string, string) Hashtbl.t
let add zone_items key content =
Hashtbl.add zone_items key content
let getCount zone_items = Hashtbl.length zone_items
end
You can also use classes. They are designed to support objects with state. Objects · OCaml Documentation. But the popular opinion these days is to use classes (objects) only when you need inheritance with what in C++ would be called virtual methods. (In OCaml all methods are virtual and the keyword virtual means what in C++ would be called abstract.)