From: "David Allsopp" <dra-news@metastack.com>
To: "OCaml List" <caml-list@inria.fr>
Subject: [Caml-list] Module design
Date: Sat, 20 Aug 2011 15:31:00 +0100 [thread overview]
Message-ID: <000701cc5f45$caa14310$5fe3c930$@metastack.com> (raw)
I'm working on a new version of a framework for a server daemon which can
have custom functionality plugged in through different backends. The present
version works by passing a record containing lots of options along the lines
of:
type backend = {b_connect: (connectionID -> bool) option; b_disconnect:
(connectionID -> unit) option}
which is then passed to a function run which does the actual work, using the
callbacks given in the backend record or substituting defaults where None is
specified.
I'm thinking that a functor would be a much neater way of doing this (and
would also allow for passing around more than just a connectionID if
required) but wondering what the best way of preserving the ability to have
default handlers for functions which a given backend isn't interested in.
I've not really used the module system beyond trivial functor applications
(Set and Map, etc.) but I've come up with the following:
(* Framework.ml *)
(* Individual connection identifiers *)
type connectionID = int
(* Wrapper type for custom connections *)
module type CONNECTION = sig
type t
val newConnection : connectionID -> t
end
(* Actual backend type *)
module type BACKEND =
sig
include CONNECTION
(* Toy functions, obviously *)
val connect : t -> bool
val disconnect : t -> unit
end
(* Default behaviour defined in these two modules *)
module Default = struct
(* Default connection information is just the identifier *)
module Connection : CONNECTION = struct
type t = connectionID
let newConnection connectionID = connectionID
end
(* Default functions *)
module Backend (C : CONNECTION) = struct
let connect _ = (* ... *)
let disconnect _ = (* ... *)
end
end
module Make (Backend : BACKEND) = struct
let run () = (* ... *)
end
and so an implementation using default connection IDs could be written:
module rec MySimpleBackend : Framework.BACKEND = struct
include Framework.Default.Connection
include Framework.Default.Backend(MySimpleBackend)
let connect _ = (* Alternate behaviour *)
(* Default disconnect is fine *)
end
and one with more complex connectionIDs could be written:
module rec MyComplexBackend : Framework.BACKEND = struct
type t = {ci_id : Framework.connectionID; (* ... *) }
let newConnection id = {ci_id = id; (* ... *) }
include Framework.Default.Backend(MyComplexBackend)
let connect {ci_id; (* ... *)} = (* Alternate behaviour *)
end
This pattern seems to work OK but is there an even neater way I haven't
spotted? I'm presuming that in the following:
module Foo = struct let x = true let x = false end
the compiler doesn't create a module with two fields one of which is
inaccessible which would seem to be important (from an aesthetic sense) with
having a module of default functions which get "overridden".
Any guidance/comment appreciated!
David
next reply other threads:[~2011-08-20 14:31 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-08-20 14:31 David Allsopp [this message]
2011-08-20 16:39 ` pierrchp
[not found] ` <1313857880.4e4fe158e4d24@imp.free.fr>
2011-08-20 20:47 ` David Allsopp
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='000701cc5f45$caa14310$5fe3c930$@metastack.com' \
--to=dra-news@metastack.com \
--cc=caml-list@inria.fr \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox