Embedding "database" features into other modules. First-class modules are allowing me to neatly unpack table implementations into other modules, using local types. This is really quite basic, but I wonder if I could have done this before first-class modules, and without leveraging the object system? I also don't recall seeing first-class modules used for something like this. So, is there another way to do this, aside from the object system? It's very much like creating a basic object. This is an extracted and simplified example... -------------------- module Db = struct (* Signature for a single 'table' in the database, elements of type t. *) module type S = sig (* Full implementation relies on a Key module for different key types than 'int' *) type t val get : int -> t val set : int -> t -> unit val del : int -> unit val iter : (int -> t -> unit) -> unit val fold : (int -> t -> 'a -> 'a) -> 'a -> 'a end (* Instantiates storage for a table, and returns FC module to interact with the store. *) let create_with_default (type s) ?(size=19) default = (* Full implementation is parameterized by Key and Table modules *) let h = Hashtbl.create size in let module H = struct type t = s let get (id:int) = try Hashtbl.find h id with Not_found -> default let set id (v:t) = Hashtbl.replace h id v let del id = Hashtbl.remove h id let iter f = Hashtbl.iter f h let fold f init = Hashtbl.fold f h init end in (module H : S with type t = s) end (* An example table... *) module Location = struct let unknown = "Unknown" include (val (Db.create_with_default unknown) : S with type t = string) (* Location might have a bunch of other functionality as well... *) end (* and basic usage... *) # Location.get 1;; - : Location.t = "Unknown" # Location.set 1 "Mars";; - : unit = () # Location.get 1;; - : Location.t = "Mars" -------------------- Some background on what this is for: (skip unless you're interested!) I use a "component architecture" with most games -- basically a database of properties keyed off "game object IDs". I thought this was a very powerful feature in old MUDs/MUSHs. It's one of the first things I tried making when I started in OCaml, but I had some difficulties and ended up explicity instantiating hashtables or maps in the global context of various modules. Sloppy, but workable. (The reason I had difficulty is because I was trying to create a database of tables which were created at runtime -- not statically known.) Recently I decided to fix this mess. I had many modules, each which tended to have a corresponding "table". Eg. Characteristics, Size, Wounds, Faction, Inventory, etc. So ideally I wanted a convenient way to embed "database" functions into such modules while declaring the implementation of the underlying datastore (hashtable, map, whatever). This might seem a bit ugly from a functional-programming perspective, but I've found components to be quite powerful, and overall helps to constrain where and how mutation happens. "Game state" is generally in flux -- well, it is everything variable, and can be compared closely with save-game state. Most code which doesn't update game state can be functional. Actually, it feels creepy to have a variable assignment in the code, since mutation is generally to game-state and that's handled through a database. So the resulting style is functional+database. -Tony