|Anonymous | Login | Signup for a new account||2018-01-19 18:47 CET|
|Main | My View | View Issues | Change Log | Roadmap|
|View Issue Details|
|ID||Project||Category||View Status||Date Submitted||Last Update|
|0007102||OCaml||typing||public||2015-12-18 16:52||2017-04-13 13:18|
|Target Version||Fixed in Version|
|Summary||0007102: Ability to re-export a variant definition with renamed constructors?|
|Description||We have a bit of an issue in Batteries for the 4.03 transition, as 4.03+dev includes a ('a result) type defined as|
type ('a,'b) result = Ok of 'a | Error of 'b
while Batteries has distributed forever a datatype
type ('a, 'b) result = Ok of 'a | Bad of 'b
This should, of course, not be blocking for the addition of a result type in 4.02.3, but it would be nice if it were possible to provide a smooth transition path to our users. (We can provide both datatypes, using type-directed constructor disambiguation, but there is still the issue that a number of functions return values of BatPervasives.result type, and we'd rather not duplicate them to have versions returning Pervasives.result).
Would it be possible to declare an alias with constructors of the same structure, but different names?
type ('a, 'b) result = ('a, 'b) Pervasives.result =
| Ok of 'a
| Bad of 'b
|Tags||No tags attached.|
If we allow to rename constructors, this should be made explicit, not relying on the ordering of constructors.
type ('a, 'b) result = ('a, 'b) Pervasives.result = | Ok of 'a | Error as Bad of 'b
Unfortunately, I'm afraid this feature first requires some theoretical work.
A first problem is that it breaks the type-erasure semantics of the language: now two constructors are equal if they have the same type (otherwise you cannot compare them) and same name. If they are allowed to have different names, then constructors are something else.
A second problem, which is a consequence of the first, is the interaction with constructor disambiguation. Suppose that you define
type t = A | B
in some module M1, and re-export it as
type u = M1.t = A as C | B as D
type v = M1.t = A as D | B as C
Then you have in the same scope two constructors C and D, which belong to the same type, and whose resolution is ambiguous...
Maybe there is a proper way to do that, but this requires some fundamental work.
Moreover, since this changes the semantics, I would see this as a change to the language itself (not just a comfort improvement, like constructor/field disambiguation or inline records).
edited on: 2015-12-21 10:11
This is probably due to my very naive point of view, but I don't see
so many difficulties.
> A first problem is that it breaks the type-erasure semantics of the
> language: now two constructors are equal if they have the same type
> (otherwise you cannot compare them) and same name. If they are allowed
> to have different names, then constructors are something else.
I understand the feature as the ability to rebind constructors to
a different name while preserving equality information (in fact using
Alain's explicit syntax one could even rebind a constructor inside its
own declarations: type 'a option = None | Nothing as None | Some of
'a). This means that we need a resolution environment for constructors
(canonicalization/rewriting of constructors), but it is not
incompatible with a type-erased semantics:
- you can perform resolution statically as an elaboration pass,
replacing occurences of Bad by Error (for example during
type-checking), which is not in the spirit of type-erasure; but
- you can also maintain a runtime environment of constructor
definitions, to be used at construction time (Bad v -> Error v)
and dually at pattern-matching time (Error p -> Bad p).
The elaboration semantics is just a partial-evaluation optimization of
the type-erased runtime semantics, where those rewriting are done
statically instead of at runtime.
> A second problem, which is a consequence of the first, is the interaction with constructor disambiguation. Suppose that you define
> type t = A | B
> in some module M1, and re-export it as
> type u = M1.t = A as C | B as D
> type v = M1.t = A as D | B as C
> Then you have in the same scope two constructors C and D, which belong to the same type, and whose resolution is ambiguous...
This situation can be rejected at declaration-time (or lazily whenever
C needs to be resolved), because the canonicalization environment for
constructor names is inconsistent (C is bound to two
incompatible constructors). If we had designed the feature before
type-directed resolution, we would have probably adopted a shadowing
semantics, but now that all constructors are "in scope" from their
type we shall accordingly guarantee that all their bindings are consistent.
> Maybe there is a proper way to do that, but this requires some
> fundamental work. Moreover, since this changes the semantics,
> I would see this as a change to the language itself (not just
> a comfort improvement, like constructor/field disambiguation or
> inline records).
Ok, we'll have to find another solution then.
|2015-12-18 16:52||gasche||New Issue|
|2015-12-18 17:43||frisch||Note Added: 0015176|
|2015-12-21 03:05||garrigue||Note Added: 0015180|
|2015-12-21 09:32||gasche||Note Added: 0015182|
|2015-12-21 10:11||gasche||Note Edited: 0015182||View Revisions|
|2017-02-23 16:45||doligez||Category||OCaml typing => typing|
|2017-04-13 13:18||doligez||Status||new => acknowledged|
|Copyright © 2000 - 2011 MantisBT Group|