How to implement mixins in the OCaml module system.
The closest I achieved is to use the following methodology, which I illustrate on a MixinFormat
which adds usual output functions print
, output
and to_string
on a mixin able to format
.
Assume that we implement a module MixinFormat
with the following signature:
module MixinFormat :
sig
(** Formatable mixin. *)
(** Input signature of the functor [MixinFormat.Make]. *)
module type Basis =
sig
type t
(** The type of formatted elements. *)
val format : Format.formatter -> t -> unit
(** [format fft a] pretty prints [a] on [fft]. *)
end
(** Output signature of the functor [MixinFormat.Make]. *)
module type Methods =
sig
type t
val to_string : t -> string
(** Convert to string. *)
val output : out_channel -> t -> unit
(** Output on the given output channel. *)
val print : t -> unit
(** Output on the standard output channel. *)
end
(** Functor implementing output mixins based on a format definition. *)
module Make(B:Basis): Methods
with type t := B.t
(** Signature of formatable mixins. *)
module type S =
sig
type t
include Basis with type t := t
include Methods with type t := t
end
end
We can now use it to add common output functions to a module able to format
, as in:
module Date =
struct
module Prototype =
struct
type t = int * int * int
let format ppt (y,m,d) =
Format.fprintf ppt "%04d-%02d-%02d" y m d
end
include Prototype
include MixinFormat.Make(Prototype)
end
This works very well but has the convenient that it is not easily iterable: if a second mxin expects functions added to Prototype
by MixinFormat.Make
then we need to pack Prototype
and MixinFormat.Make(Prototype)
in Prototype2
which is a bit clumsy and hinders readability.
Is there an alternative implementation of mixins which could avoid to introduce a Prototype2
when iteratively using mixins?