Why conv(foo) 's converter module is Foo_conv, not Foo?
Because the converter module should be opened.
Target data module Foo is often implemented independently of Meta_conv, and its default primitive converters could be written by a 3rd party. There are two ways to add converters:
Implement converter specific module, say Foo_conv.
module Foo = struct include Foo (* code of converters *) end
One of the important design rules of Meta_conv is that the primitive converters must be accessible without module paths. (CR jfuruse: I should explain why.) This enforces users to open the modules of primitive converters.
open Foo_conv is ok since it is specialized for Meta_conv converters. But open Foo may have cause unwanted name contamintation.
Therefore, Foo_conv, not Foo.
Why conv(foo) 's target type is Foo.t, not foo?
Because conv() can have multiple targets!
Think about conv(json, ocaml), and the target type names were json and ocaml. Then we have name corrisions: json_of_ocaml is an encoder to json or a decoder of ocaml? ocaml_of_json is a decoder of json or an encoder to ocaml?
To distinguish them, the target type must be module prefixed like:
Json.t_of_ocaml : Ocaml.t -> Json.t Json.ocaml_of_t : ?trace:_ -> Json.t -> (Ocaml.t, _) Result.t Ocaml.t_of_json : Json.t -> Ocaml.t Ocaml.json_of_t : ?trace:_ -> Ocaml.t -> (Json.t, _) Result.t
Then, why not the target type is Foo_conv.t, or Foo_conv.Target.t?
Because Foo_conv is supposed to be opened. t and Target.t could corride with other target types.