Mantis Bug Tracker

View Issue Details Jump to Notes ] Issue History ] Print ]
IDProjectCategoryView StatusDate SubmittedLast Update
0005480OCamlOCaml generalpublic2012-01-17 10:002012-01-23 11:48
Reporterfrisch 
Assigned To 
PrioritynormalSeverityfeatureReproducibilityhave not tried
StatusacknowledgedResolutionopen 
PlatformOSOS Version
Product Version 
Target VersionFixed in Version 
Summary0005480: Compilation units as recursive modules
DescriptionA compilation unit X with an implementation x.ml and an interface x.mli is morally interpreted as the following declaration:

  module X : sig
     [content of x.mli]
  end = struct
     [content of x.ml]
  end


What about interpreting it instead as a recursive module declaration:

  module rec X : sig
     [content of x.mli]
  end = struct
     [content of x.ml]
  end


This would make it possible to refer, in x.ml, to components defined further down in the same file and even to structural types (and class types, module types) defined in x.mli to avoid code duplication.
TagsNo tags attached.
Attached Files

- Relationships

-  Notes
(0006700)
hcarty (reporter)
2012-01-17 19:05

This is an interesting proposal. What effect would this have on redefined values? For example:

x.mli:
  val f : int -> int
  val g : int -> int

x.ml:
  let g x = x + 1
  let f x = g x
  let g x = x + 2

Which g is f using in your proposed case? Should one expect it to be the g exposed in the .mli or the g defined prior to f? Would "include X" be required at the top of x.ml to see types only defined in x.mli, or types/values defined later in the module?
(0006701)
frisch (developer)
2012-01-17 21:11

Scoping rules would be the same as for the "module rec" expansion. To refer to a definition further down in the module, you need to prefix with the module name explicitly.

In your example, "f" uses the first "g". To use the second one, you would write
"X.g".
(0006712)
hcarty (reporter)
2012-01-17 23:49

Under 3.12.1:

module rec X : sig
  type t = A | B | C
  val f : t -> string
  val g : t -> string
end = struct
  type t = A | B | C
  let f = X.g
  let g = function A -> "a" | B -> "b" | C -> "c"
end

X.(f A) raises an Undefined_recursive_module exception. Would this still be the case under your proposal if X is split into x.ml and x.mli?

If t is not included fully in both the sig and struct sections then g fails with a compilation error. Would this duplication requirement change under your proposal?
(0006713)
gasche (developer)
2012-01-17 23:56
edited on: 2012-01-17 23:57

Note that you can remove the exception by eta-expanding f:

  let f x = X.g x

The idea is that, under a backpatching semantics, "let f = X.g" would force X at definition time, which results in an undefined function `f`, while "let f x = X.g" only accesses X.g at `f` application time, which is after the X module has been fully built. See the manual for more details:
  http://caml.inria.fr/pub/docs/manual-ocaml/manual021.html#toc75 [^]

(0006714)
frisch (developer)
2012-01-18 07:24

It could be useful to improve the compilation strategy for recursive modules so as to cover more cases, but this is rather independent from the proposal.

Concerning the duplication of type declarations: currently, recursive modules makes it possible to avoid duplication of structural type elements. For instance, your example with polymorphic variants. Or the following:

module rec X : sig
  module type S = sig type t = A | B | C end
  include S
end = struct
  module type S = X.S
  module rec Y : S = Y
  include Y
end

One could also consider adding a "type-include" mechanism, that would allow to write:

module rec X : sig
  type t = A | B | C
end = struct
  include type X.t
end
(0006766)
lefessan (developer)
2012-01-22 22:51

I submitted a patch a while ago to improve the compilation strategy for recursive modules (0005286).

Without this patch, I think a lot of programs would not compile if all units were recursive by default. Have you tried to compile some non-trivial applications with this patch ?
(0006768)
frisch (developer)
2012-01-23 09:07

Fabrice, unfortunately, I haven't tried your patch.

At LexiFi, we have used a simpler form of the proposal for some time; in our version, compilation units are type-checked as recursive modules (which allows nice type-level forward references and references from the implementation to the interface) but compiled as usual (compile-time error if we use module recursion to refer to a dynamic component).
(0006770)
xleroy (administrator)
2012-01-23 11:48

I know for a fact that recursive modules in OCaml are a bit of a hack, in that the typechecking is incomplete and the compilation can fail at run-time in rather mysterious ways. That's tolerable as long as recursive modules are clearly marked as an experimental language extension. But I'm extremely wary of putting them at the heart of OCaml, so to speak, namely in the processing of compilation units. That's just calling for major trouble.

- Issue History
Date Modified Username Field Change
2012-01-17 10:00 frisch New Issue
2012-01-17 19:05 hcarty Note Added: 0006700
2012-01-17 21:11 frisch Note Added: 0006701
2012-01-17 23:49 hcarty Note Added: 0006712
2012-01-17 23:56 gasche Note Added: 0006713
2012-01-17 23:57 gasche Note Edited: 0006713 View Revisions
2012-01-18 07:24 frisch Note Added: 0006714
2012-01-22 22:51 lefessan Note Added: 0006766
2012-01-23 00:27 gasche Status new => acknowledged
2012-01-23 09:07 frisch Note Added: 0006768
2012-01-23 11:48 xleroy Note Added: 0006770


Copyright © 2000 - 2011 MantisBT Group
Powered by Mantis Bugtracker