-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
Original bug ID: 6000
Reporter: @lpw25
Assigned to: @lpw25
Status: closed (set by @xavierleroy on 2015-12-11T18:26:28Z)
Resolution: fixed
Priority: normal
Severity: minor
Version: 4.01.0+dev
Target version: 4.02.0+dev
Category: typing
Related to: #5759
Monitored by: @gasche @lpw25 @hcarty yminsky
Bug description
We have had record disambiguation on trunk now for a few months,
and I think that it would be wise to look again at the issue of
out of scope labels and constructors before the next major
release.
The issue is around the new ability to use a constructor or label
even though that constructor or label is not in scope, as long as
the type information is available.
For example, the following is allowed:
module M = struct
type foo = Foo
end
let x: M.foo = Foo
Note that previously this would be rejected, forcing the user to
write:
let x = M.Foo
Currently, using this feature produces a warning (40 "Constructor
or label name used out of scope"), however I think that it should
be upgraded to a full error.
This was discussed in #5759, however more issues have emerged
since that discussion, and I think now is a good time to
re-evaluate this descision.
My arguments against allowing out of scope labels and
constructors are as follows:
-
It allows references to constructors to be used in files that
contain no reference to the file defining those
constructors. For example, I have already come across the
following code in the wild:(* types.ml *)
...
module Project = struct
...
type project = {
project_id: string;
...
}
...
end
...(* data.ml *)
...
open Types
...
module Projects = struct
open Project
module Platform = structlet project = { project_id="platform"; ... } ... end ... let all = [ Platform.project; ... ] ... end(* gantt.ml *)
...
open Data
...
List.map Projects.all
~f:(fun proj -> ... proj.project_id ...)
...Note that gantt.ml uses project_id but contains no reference to
types.ml where that label is defined. When a bug occurred, it
was non-trivial to fix due to the difficulty of finding the
appropriate definition of project_id. This bug caused a lot of
confusion among less experienced OCaml programmers, and I think
that it is a very bad idea to allow it. -
It only works "in the presence of type information". This is an
unspecifed criteria that most users will probably find
confusing. -
It doesn't work with GADTs. If the constructor in question is
declared using GADT syntax then it cannot be used out of scope. -
It can't work with exceptions.
-
It won't work with "open types" (Open Extensible Types #5584) or "pattern synonyms"
which may be added to the language in future. -
It will confuse users by adding a small element of structural
typing to an otherwise nominative system. I think that most
users picture variant constructors as named values, and all
named values in OCaml obey the same scoping rules. To suddenly
allow these values to be used as if they were not named values,
but structural values (like the methods in an object) will
confuse people.
In return for these issues, all that we gain is the ability to
refer to out of scope constructors and labels without using a
module name, but only under certain difficult to define
conditions.
Last time that this issue was discussed, it only appeared to be
discussed by 4 people. I think perhaps it would be a good idea
to get wider feedback before including a potentially risky
feature like this in a release.
It is also worth pointing out that it would be easier to add this
feature in the future than to remove it later if it causes
problems.