Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

can't redefine modules #6917

Closed
vicuna opened this issue Jun 26, 2015 · 7 comments
Closed

can't redefine modules #6917

vicuna opened this issue Jun 26, 2015 · 7 comments

Comments

@vicuna
Copy link

vicuna commented Jun 26, 2015

Original bug ID: 6917
Reporter: @sliquister
Status: acknowledged (set by @damiendoligez on 2015-07-22T14:28:13Z)
Resolution: open
Priority: normal
Severity: feature
Target version: later
Category: typing
Monitored by: @gasche @diml

Bug description

We can't write things like:

include struct
module A = struct type t = A end
module A = struct include A let x = A end
end

because of this:

Error: Multiple definition of the module name A.
Names must be unique in a given structure or signature.

This is sometimes useful, for instance:

include Core.Std
module List = struct
include List
..
end

Since a few versions ago, we have 'module type of', so we can write:

include (Core.Std : module type of struct include Core.Std end with module List := Core.Std.List)
module List = struct
include Core.Std.List
..
end

although 'module type of' probably forces the compiler to expand
module aliases and read extra cmis for no reason. And it's worse
if you want to extend a module inside a module.

Can't you allow to write the straightforward thing? The compiler can
handle redefinitions, provided we hide them, so why not allow them?
Maybe it could be a warning instead.

Here is why I say the compiler can already handle the redefinitions:

include struct
module A = struct type t = A end
module A = struct include A let x = A end
end

can be understood, assuming we had let bindings at the module level:

include
let module A = struct type t = A end in
let module A = struct include A let x = A in
struct module A = A end

and by rewriting the let bindings into module level beta-redexes,
we can feed it to the compiler and it does the right thing:

include

(functor(A : module type of struct type t = A end) ->
  (functor(A : module type of struct include A let x = A end) ->
    struct module A = A end)
   (struct include A let x = A end))
(struct type t = A end)

module A : sig type t = A val x : t end

@vicuna
Copy link
Author

vicuna commented Jun 26, 2015

Comment author: @alainfrisch

Of course we can't allow module redefinition in general, since it could leave dangling type-paths or change their meaning:

module A = struct t = X end
let x : A.t = A.x
module A = struct t = Y end

What you suggest is that redefinition might be safe in some cases. Is is indeed always the case when the module type of the new module is a subtype of the previous one? (and even when restricting only to type-level components in the module types?) In practice, this would allow the case where the new module includes the previous one (and perhaps redefine some values).

@vicuna
Copy link
Author

vicuna commented Jun 26, 2015

Comment author: @sliquister

Yes, it doesn't work all the time but I'm saying the compiler already has the criteria of when it works and when it doesn't.
Your example is rejected:

# include
  (functor(A : module type of struct type t = X end) ->
   struct
     let x : A.t = A.X
     include
       (functor (A : module type of struct type t = Y end) ->
        struct let x = x module A = A end)
       (struct type t = Y end)
    end)
   (struct type t = X end)
Error: This functor has type
       functor (A : sig type t = X end) ->
         sig val x : A.t module A : sig type t = Y end end
       The parameter cannot be eliminated in the result type.
        Please bind the argument to a module identifier.

@vicuna
Copy link
Author

vicuna commented Jun 26, 2015

Comment author: @sliquister

Oh, and extending a module doesn't always work, you still have the restriction that you can't use the type before it is defined:

module A = struct t = X end
let x : A.t = A.X
module A = A

fails:

include

(functor(A : module type of struct type t = X end) ->
struct
let x : A.t = A.X
include
(functor (A : module type of A) ->
struct let x = x module A = A end)
(A)
end)
(struct type t = X end)
Error: This functor has type
functor (A : sig type t = X end) ->
sig val x : A.t module A : sig type t = A.t = X end end
The parameter cannot be eliminated in the result type.
Please bind the argument to a module identifier.

@vicuna
Copy link
Author

vicuna commented Jun 26, 2015

Comment author: @alainfrisch

Oh, and extending a module doesn't always work

The issue would be that in the inferred signature, the definition for A comes after the one for x, if we shadow the first definition. But if we don't, the signature would be:

module A : sig type t = X end
val x: A.t
module A : sig type t = A.t = X end

I'm not convinced that allowing such signatures is safe, but I don't find a simple counter-example (and it certainly requires some extra work in the compiler).

@vicuna
Copy link
Author

vicuna commented Sep 30, 2015

Comment author: @sliquister

By the way, include (A : module type of struct include A end) expands all the aliases in A, which in the case of Core.Std makes for unnecessarily large cmt files.

@github-actions
Copy link

This issue has been open one year with no activity. Consequently, it is being marked with the "stale" label. What this means is that the issue will be automatically closed in 30 days unless more comments are added or the "stale" label is removed. Comments that provide new information on the issue are especially welcome: is it still reproducible? did it appear in other contexts? how critical is it? etc.

@github-actions github-actions bot added the Stale label May 11, 2020
@xavierleroy
Copy link
Contributor

A fundamental property of the OCaml type system is that type constructors are identified by paths. This in turn requires that module and type names be unique in a structure. We're not going to make exceptions (that would probably be unsound anyway) just so that one library looks better.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants