Mantis Bug Tracker

View Issue Details Jump to Notes ] Issue History ] Print ]
IDProjectCategoryView StatusDate SubmittedLast Update
0006333OCamlOCaml typingpublic2014-02-28 18:372014-05-16 20:51
Reporterfrisch 
Assigned Togarrigue 
PrioritynormalSeverityminorReproducibilityhave not tried
StatusresolvedResolutionfixed 
PlatformOSOS Version
Product Version 
Target Version4.02.0+devFixed in Version4.02.0+dev 
Summary0006333: Keep equation on module type while strengthening
DescriptionI suggest to modify the strengthening of module type bindings in signatures in order to keep the equation to the original module type (as we currently do for abstract module types). Concretely, one would change in Mtype.strengthen_sig:


  | Sig_modtype(id, decl) :: rem ->
      let newdecl =
        match decl.mtd_type with
          None ->
            {decl with mtd_type = Some(Mty_ident(Pdot(p, Ident.name id, nopos)))}
        | Some _ ->
            decl
      in
      ...

into:

  | Sig_modtype(id, decl) :: rem ->
      let newdecl =
            {decl with mtd_type = Some(Mty_ident(Pdot(p, Ident.name id, nopos)))}
      in
      ...

This changes makes sense, since module type now have a nominal aspect, because of first-class modules.

Several examples of code which would benefit from the change have been posted on the caml-list ("First class modules aliases" thread, Feb. 2014).

Would there be any drawback from this change?
Tagspatch
Attached Filesdiff file icon structural_packages.diff [^] (11,012 bytes) 2014-03-04 05:23 [Show Content]

- Relationships
related to 0006159resolvedgarrigue Non backward compatible change in type comparison 

-  Notes
(0010982)
garrigue (manager)
2014-03-03 09:00

There is the same problem as with module aliases: since type information is not duplicated, a new dependence on the source is introduced.
Here is an example:
a/a.ml:
module type S = sig val x : int end
b.ml:
include A
c.ml:
module M : B.S = struct let x = 2 end

compiled with:
ocamlc -c a/a.ml
ocamlc -I a -c b.ml
ocamlc -c c.ml

This would not work anymore, and I do not even see a workaround (we are already using include here).

If we really see module types as having a nominal aspect, the correct thing to do would rather be to add a separate "manifest" field, just like for type definitions.
Another approach would be to make them "more" structural, i.e. to check equivalence of signatures, at least in simple cases.
This shouldn't be that hard in practice, but we delayed it until now.
(0010983)
frisch (developer)
2014-03-03 11:44

Do you think it is going to be a problem in practice? If the user deliberately wants to hide a.cmi when compiling c.ml, he could accept the burden of creating a proper b.mli which expands the definition for S. And one could also argue that keeping a symbolic reference to A.S reduces the size of b.cmi, which is nice.

Otherwise, would it be possible to expand module type aliases only while saving the signature?

And yes, a solution based on a more structural comparison of package types would probably be a nicer approach to fixing this.
(0010989)
garrigue (manager)
2014-03-04 05:25

I just uploaded a patch that does the "right thing".
I.e., provide structural comparison and subtyping for first-class module signatures.
This should not be that costly.
The only thing we loose is that it becomes very hard to ensure that two signatures
are incompatible, so if you use them as type indices you won't be able to discard cases.
(Which I think doesn't matter at all)
Here are a few examples using it:

module type S = sig type u type t end;;
module type S' = sig type t = int type u = bool end;;

(* ok to convert between structurally equal signatures, and parameters
   are inferred *)
let f (x : (module S with type t = 'a and type u = 'b)) = (x : (module S'));;
let g x = (x : (module S with type t = 'a and type u = 'b) :> (module S'));;

(* with subtyping it is also ok to forget some types *)
module type S2 = sig type u type t type w end;;
let g2 x = (x : (module S2 with type t = 'a and type u = 'b) :> (module S'));;
let h x = (x : (module S2 with type t = 'a) :> (module S with type t = 'a));;
let f2 (x : (module S2 with type t = 'a and type u = 'b)) =
  (x : (module S'));; (* fail *)
let k (x : (module S2 with type t = 'a)) =
  (x : (module S with type t = 'a));; (* fail *)

(* but you cannot forget values (no physical coercions) *)
module type S3 = sig type u type t val x : int end;;
let g3 x =
  (x : (module S3 with type t = 'a and type u = 'b) :> (module S'));; (* fail *)
(0010990)
garrigue (manager)
2014-03-04 06:39

By the way, there remains another question: whether to allow using first class modules without defining a module type in advance.
Since comparison is now structural, there is no obstacle to do that.
On the other, you probably don't want to see such types printed, just like with objects...
(0011032)
garrigue (manager)
2014-03-10 03:07

Structural comparison of first class module types merged into trunk at revision 14450.

- Issue History
Date Modified Username Field Change
2014-02-28 18:37 frisch New Issue
2014-03-03 09:00 garrigue Note Added: 0010982
2014-03-03 11:44 frisch Note Added: 0010983
2014-03-04 05:23 garrigue File Added: structural_packages.diff
2014-03-04 05:25 garrigue Note Added: 0010989
2014-03-04 05:25 garrigue Assigned To => garrigue
2014-03-04 05:25 garrigue Status new => feedback
2014-03-04 06:39 garrigue Note Added: 0010990
2014-03-10 03:07 garrigue Note Added: 0011032
2014-03-10 03:07 garrigue Status feedback => resolved
2014-03-10 03:07 garrigue Fixed in Version => 4.02.0+dev
2014-03-10 03:07 garrigue Resolution open => fixed
2014-04-04 05:10 garrigue Relationship added related to 0006159
2014-05-16 20:51 doligez Tag Attached: patch


Copyright © 2000 - 2011 MantisBT Group
Powered by Mantis Bugtracker