Using module type of with module aliases in OCaml 4.07.*

I am in the process of upgrading a codebase from ocaml 4.06.1 to 4.07.1. I believe I ran into a change related to this PR. Below is a example of the error and how to work around it. However, the PR thread alludes to a more sound module composition strategy that avoids the use of the [@remove_aliases] annotation. Does anyone know how to “modernize” the code below so no annotation is required?


module X = struct 
  type t = int 
  let add t t' = t + t' 
end

module T = struct module X = X end

(* Compiles with ocaml 4.06.1 but not 4.07.1. Yields following error:

Error: In this `with' constraint, the new definition of X
       does not match its original definition in the constrained signature:
       Modules do not match: (module X) is not included in (module X)
*)
module T2 = struct 
  module X = struct include X let sub t t = t - t end
  include (T: module type of T with module X := X)
end


(* Adding the [@remove_aliases] annotation makes it compile with 4.07.1. *)
module T3 = struct 
  module X = struct include X let sub t t' = t - t' end
  include (T: module type of T [@remove_aliases] with module X := X)
end

Thanks in advance! As a bonus, I wouldn’t mind a layman’s explanation of what makes the original solution incorrect or undesirable. I’ve used the above pattern fairly often and want to unwind any antipatterns I’ve acquired over the years as an OCaml developer.

You should replace:

include (T: module type of T with module X := X)

with:

include (T: module type of T with module X := T.X)

Even before 4.07.0 the second is actually more reliable. If T had included something like:

val x : Foo(X).t

then the second one would work but the first one wouldn’t.

It’s probably also worth noting that in 4.08 you’ll be able to avoid this pattern entirely an just write:

module T2 = struct 
  include T
  module X = struct include X let sub t t = t - t end
end
2 Likes