caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Lauri Alanko <la@iki.fi>
To: caml-list@inria.fr
Subject: [Caml-list] Avoiding ml/mli code duplication
Date: Tue, 28 Dec 2010 16:02:47 +0200	[thread overview]
Message-ID: <20101228140247.GB12021@melkinpaasi.cs.helsinki.fi> (raw)

A common grievance with ML-style module systems is duplication of code
between the interface and the implementation of a module. In
particular, transparent type and signature definitions must be present
in both. This is annoying because of the extra work required to keep
both copies in sync.

To an extent, this can be avoided. Consider the following:


(*** Foo.mli ***)
(* Transparent definitions *)
type t = ...
module type S = sig ... end
(* Opaque definitions depending on the above *)
val x : ... t ...
module M : ... S ... t ...

(*** Foo.ml ***)
(* Transparent definitions duplicated *)
type t = ...
module type S = sig ... end
(* Definitions for the opaques *)
let x = ...
module M = ...


Here the common transparent definitions can be moved into a separate
wholly transparent module:


(*** FooDefs.ml ***)
type t = ...
module type S = sig ... end

(*** Foo.ml ***)
include module type of FooDefs (* or open FooDefs *)
val x : ... t ...
module M : ... S ... t ...

(*** Foo.mli ***)
include FooDefs (* or open FooDefs *)
let x = ...
module M = ...


So far so good. But in the real world, the situation is often more
complicated: we have transparent definitions that depend on opaque
definitions. Like this:


(*** Bar.mli ***)
(* Opaque *)
type t
(* Transparent depending on above *)
type u = ... t ...
(* Opaque depending on above *)
val x : ... u ...

(*** Bar.ml ***)
type t = ...
type u = ... t ...
let x = ...


Keep in mind that in actuality the "type u" line can represent huge
amounts of type and signature definitions, so there is real need to
avoid duplication.

In this situation, I'm not quite sure what's the best way to
proceed. Here's what I have currently:

(*** BarDefs.ml ***)
module type CORE = sig
  (* Primitive opaque definitions that the transparents depend on *)
  type t
end
module Make(Core : CORE) = struct
  include Core
  (* Transparent definitions *)
  type u = ... t ...
end

(*** Bar.mli ***)
module Core : BarDefs.CORE
include module type of BarDefs.Make(Core)
val x : ... u ...

(*** Bar.ml ***)
module Core = struct
  type t = ...
end
include BarDefs.Make(Core)
let x = ...


This does the job, but I'm not quite satisfied. It feels wrong that I
have to define a functor when I will only ever apply it once. Also,
the "include module type of" is a recent feature, and it's hard to
believe there's no solution to this problem before OCaml 3.12.

I'd appreciate any suggestions for better solutions.


Lauri

             reply	other threads:[~2010-12-28 14:03 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-12-28 14:02 Lauri Alanko [this message]
2010-12-28 14:16 ` Richard W.M. Jones
2010-12-28 14:59 ` Alain Frisch
2010-12-28 16:54   ` Lauri Alanko

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=20101228140247.GB12021@melkinpaasi.cs.helsinki.fi \
    --to=la@iki.fi \
    --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;
as well as URLs for NNTP newsgroup(s).