Error: this open statement shadows the label name (which is later used)


#1

Me again.

I’m encountering a compiler warning of “this open statement shadows the label name (which is later used)”.

It’s supposedly caused by opening a module to which my working module already has visibility. This I understand, but I don’t get this error in every module, even though the visibility should be the same.

Further, adding “!” after the open statement removes the warning. I can’t find explanations of the exclamation point on statements anywhere in the docs. Is this only Reason or also OCaml?


#2

The warning and the syntax are both originally from OCaml. The warning means that you have an already-defined identifier name, then you’re opening a module which also contains the identifier name, which is shadowing the original one. This can lead to subtle bugs so I would always look at why there is shadowing happening in the first place. Try to narrow down the scope of the module open as much as possible (which is a best practice in OCaml/Reason). open! should be an absolute last resort.

See http://caml.inria.fr/pub/docs/manual-ocaml-4.01/extn.html#sec236


#3

I discovered why the error wasn’t being thrown for the other module. The shadowing wasn’t technically occurring. Is there any other place where the ! is used? It’s a strange piece of one-off syntax otherwise.


#4

I’m still not quite grasping why what I’m doing counts as shadowing.

module Staff = {
  type role =
    | Delivery
    | Sales
    | Other;
    
  type member = {
    name: string,
    role
  };
};

module NewStaff = {
    open Staff;
    let newRole = Delivery;
    let newEmployee: member = {name: "Fred", role: Other};
};

The open Staff line throws the shadow error only if newEmployee is included. Why?


#5

I don’t remember off-hand if ! is syntactically used like that anywhere else. I do agree that it feels somewhat out of place.

Regarding your example, I’m actually not seeing any compiler warning when I try it in the Reason playground. I am able to reproduce the warning with the following code:

module A = {
  type a = {name: string};
};

module B = {
  type b = {name: string};
  open A; // Warning 45: this open statement shadows the label name (which is later used)
  let b1 = {name: ""}; // Actually has type A.a
};

As you can see, this is happening because different record types use the same label names. This can lead to quite a lot of confusion, hence it’s almost always better to avoid fully opening modules to access their record labels and constructors. Instead, it’s better to prefix only a single field of the record when you want to pinpoint its exact module and type, e.g. let a1 = {A.name: ""};


#6

Bah. Found it. Much earlier in my huge monolith of phutzcode I had used the label name “name.” That was the problem.