Unclear error message (signature not included in itself)

I do not know what to make of the following error message :

Error: The implementation pdfio.ml does not match the interface pdfio.cmi:
       Values do not match:
         val setinit_string : input -> bytes -> int -> int -> unit
       is not included in
         val setinit_string : input -> bytes -> int -> int -> unit

Does anyone know what this really means ?
As this is unfortunately from a large project I cannot post a minimal example here, but I can show the relevant snippets in the code :

In the .mli file :

(** [setinit_string i s o l] sets s o…o + l - 1 from the input *)
val setinit_string : input → bytes → int → int → unit

In the .ml file :

let setinit_string i s o l =
          let max = Bytes.length s - 1
          and last = o + 1 - 1 in
            if o > max || o < 0 || last < 0 || last > max 
            then raise (Failure "setinit_string") 
            else
              match i.caml_channel with
              | Some ch ->
                  really_input ch s o l
              | None ->
                  for x = o to o + l - 1 
                  do 
                   Bytes.unsafe_set s x (Char.unsafe_chr (i.input_byte ())) 
                  done

It is possible that the name input refers to two different types with the same name. Do you happen to define a type input inside your .ml file?

Yes, and I define it as follows :

type input =
  {pos_in : unit -> pos;
   seek_in : pos -> unit;
   input_char : unit -> char option;
   input_byte : unit -> int;
   in_channel_length : pos;
   set_offset : pos -> unit;
   caml_channel : in_channel option;
   source : string}

But since I define only one in my project, where does the second type come from ? Is it an internal built-in, or does the compiler get confused seeing double ?

There is no input type in the standard library. But it may come from another library. Or you may have defined this input type multiple times inside your project. Or maybe you redefined bytes or int. It is hard to tell without seeing your project source since the code that your shared does not trigger any error by itself. Could you try to share a reproducible example of your issue or a link to the whole project?

To get a clearer overview, how does input get declared in the mli file?

The definition in the mlfile is identical to the declaration in the mli file, and it’s the one I gave above.

After some effort, I was able to construct a smaller example with only
two files, long_file.ml and long_file.mli, available at

Here’s what I get in my terminal (and I presume most people will get the same) :

$ ls
long_file.ml	long_file.mli
$ ocamlc -c long_file.mli
$ ls
long_file.cmi	long_file.ml	long_file.mli
$ ocamlc -c long_file.ml
File "long_file.ml", line 1:
Error: The implementation long_file.ml
       does not match the interface long_file.cmi:
       ...
       In module Pdfio:
       Values do not match:
         val setinit_string : input -> bytes -> int -> int -> unit
       is not included in
         val setinit_string : input -> bytes -> int -> int -> unit
       File "long_file.mli", line 814, characters 0-57: Expected declaration
       File "long_file.ml", line 1711, characters 4-18: Actual declaration

Using a future version of OCaml 4.08 makes the error much clearer;

   In module Pdfio:
  Values do not match:
    val setinit_string : input -> bytes/2 -> int -> int -> unit>
  is not included in
    val setinit_string : input -> bytes/1 -> int -> int -> unit
  File "long_file.mli", line 814, characters 0-57: Expected declaration
  File "long_file.ml", line 1711, characters 4-18: Actual declaration
 File "long_file.ml", line 1268, characters 0-54:
    Definition of type bytes/1
  File "_none_", line 1:
    Definition of type bytes/2
2 Likes

You have indeed two different types called bytes.

In the mli file the occurence of bytes in the signature refers to the abstract type bytes you declared above, which shadowed the standard definition.

In the ml file the inferred type of your argument is the standard bytes, aka Bytes.t, since you call Bytes.length on it.

1 Like