What is warning 30 for?

If I write a code like this:

type a = B of b | C of c
and b = {str: string;}
and c = {str: string; a: a};;

I get a warning:

the label str is defined in both types b and c.

But why is this bad? What kind of issues I can have if I ignore the warning?


Originally asked at the ReScript forum.

2 Likes

If you have two types that defines the same label or constructor, distinguishing between the two types requires type-directed disambiguation. Since type-directed disambiguation is not sufficient in all context, this implies that the type of some functions becomes ambiguous

let str x = x.str (* what is the type of `x`? `b` or `c`)

and those functions require some explicit type annotation to remove the ambiguity:

let str (x:c) = x.str

However, in many cases it is not that painful to deal with the ambiguity, that is why the
the duplicate-definitions warning is disabled by default in recent versions of OCaml.

2 Likes

I thought that was the reason, but I only get the warning when the types are mutually recursive. For example this doesn’t produce a warning:

type b = {str: string;}
type c = {str: string; a: int}

So I wonder whether there some additional concerns when the types are recursive?

With mutually recursive types, the order of the type definitions is unclear, and there is no point where there is only one definition in scope. Contrarily, with a separated type definitions, you could have something like:

type t = A
let x = A
type u = A
(* ... some code that never use `A:t` *)

where it is fine to shadow A:t if it is never used again.
Thus the duplicate-definitions case is clearly always problematic without type-directed disambiguation, but the situation is slightly less clear cut with separate definitions.

3 Likes

Warning 30 was important before we supported type-based disambiguation, because those situations were always a mistake from the user. It became mostly irrelevant when disambiguation was added. But we took some time noticing, and only disabled it by default in OCaml 4.10 (see #9046). I believe that you can safely forget about it.

5 Likes

If the warning is disabled, do you know why I still see it in merlin in emacs then? The switch is ocaml 4.14.1. I have no other ocaml compiler versions installed on the machine.

My guess: you are using Dune, and released versions of dune still enable the warning by default. See Remove warning 30 from the standard set. by gasche · Pull Request #9568 · ocaml/dune · GitHub .

Thank you - yes, that’s correct. I see that the version of dune disabling this warning by default is not yet released. In the meantime, this stackoverflow solution to disable the warning works:

TL;DR: add a dune file to the root of the project containing this stanza:

(env
  (dev
    (flags (:standard -w -30))))

Then run dune build, reload (revert) the file, and the red underline highlighting the warning in emacs will disappear.

I’m not sure if you’ve considered this, but another solution that might be helpful if you don’t want to go to the trouble of creating a root dune file, or want more fine grained control is to use annotations:

[@@@warning "-30"]

at the top of your file should disable warnings for that file, or [@@warning "-30"] immediately after the location where the error is raised to disable it for a particular AST node.

If this is new code that is not meant to support older OCaml versions, I would rather use the warning name for readability:

[@@@warning "-duplicate-definitions"]

Note: the 3.13 release is now out, so the most recent versions of Dune do disable this warning by default – if the dune-project version is 3.13 or more recent.