OCaml has a flat namespace for compilation unit's names. When a compilation unit uses some module, it records the name of the module interface and a digest (basically an CRC of the interface). A consistency check ensures that two interfaces with the same name have the same digest (basically represent the same implementation). Although the error message is indeed misleading, it is still correct (although the wording could be much better). Let's use the ocamlobjinfo
tool:
$ ocamlobjinfo _build/Main/Stream.cmi
File _build/Main/Stream.cmi
Unit name: Stream
Interfaces imported:
83d31bf1e61f22b62a8b2728a55f2593 Stream
d0b21ad0c1f4e93fa8c05b9ded519b52 Stream
999b28e3b7638771c87eebf5a8325e42 Pervasives
60c2e7663dd57d13b5920931742e1c10 Format
9642e3ed163e46770985ca668738ed5f CamlinternalFormatBasics
6dc691300ced97c0e319cbcc0a715044 Bytes
3bd1af04573ce2da7fc3dc04403e852e Buffer
383683999ce4d4a54f1689bb92969ecb BatStream
fbefc52bb310bf525973099141e16ffe BatOrd
92bc9ee9d7e3da3421ed7fc5c0ade74d BatInterfaces
7d12ec9e52c91f3af313796ff85158c4 BatInnerIO
6f57ab9f63c2f00619c3ffc9bde0bc80 BatIO
bd48c0243cabeabfa9ba81aa02319882 BatEnum
1972feae99a1525e1b830ca37c4efa20 BatConcurrent
We have two interfaces imported that have the same name, but different implementations (CRC sums are different). The first interface is actually the interface of your Stream
module, the second one is the interface of the standard's Stream module:
$ ocamlobjinfo /home/ivg/.opam/devel/lib/ocaml/stream.cmi
File /home/ivg/.opam/devel/lib/ocaml/stream.cmi
Unit name: Stream
Interfaces imported:
d0b21ad0c1f4e93fa8c05b9ded519b52 Stream
999b28e3b7638771c87eebf5a8325e42 Pervasives
9642e3ed163e46770985ca668738ed5f CamlinternalFormatBasics
As you may notice each module always imports its own interface. So the conflict is between your Stream
module and OCaml's Stream
module. The standard's Stream
module got into your compilation unit via the BatStream
module.
To summarize. Interface namespace is flat, so you need to use prefixed to prevent conflicts, cf., BatStream
. Yes, it is ugly.
Module packing can help you in preventing name conflicts between modules that are packed into a package, and modules that use the package. For example, if you have a module M
packed in the package P
, then you can link it with another module M
and there will be no conflicts between M
and P.M
(if you did everything correctly). However, when you build the package, the modules constituting it, should not have conflicts with modules that they use, and, unfortunately, the OCaml standard library is not a package, so you should choose names that don't collide with the standard library or any other library that you are using for the implementation of your package.