Hello,
I’ve written a tiny ppx called ppx_mixins so that one can write:
type u [@@mixins Map.OrderedType + Printable]
which gets desugared to
type u
include Map.OrderedType with type t := u
include Printable with type t := u
Not much but increases readability in a codebase that uses the “mixin” pattern a lot
Constructing type signatures
One can also write
module type M = [%mixins Map.OrderedType + Printable]`
(* desugars to *)
module type M = sig
type t
include Map.OrderedType with type t := t
include Printable with type t := t
end
In particular, if you also overcome the lack of support for e.g. pretty printing (or other features) in the standard library by extending functors:
module type Hashed_and_printable = sig
include Stdlib.Hashtbl.HashedType
val pp : Format.formatter -> t -> unit
end
module Make (T: Hashed_and_printable) = struct
include Stdlib.Hashtbl.Make(T)
let pp = ...
end
You can instead write:
module Make(T: [%mixins Stdlib.Hashtbl.HashedType + Printable]) = struct
...
end
Additional features
One can also override other types, e.g.
type u [@@mixins Mappable(key = int; value := v)]
(* desugars to *)
type u
include Mappable with type t := u and type key = int and type value := v
Limitations
- No support for parametric types, e.g.
with type 'a u = 'a v - No support for tuple and function types, e.g.
with type t = int -> bool
This is because the preprocessor parses the payload as an expression, and these don’t parse nicely a expressions.
Deeper support (e.g. for mixins with type parameters) would probably also require language support.