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

Recursive module types #4899

Closed
vicuna opened this issue Oct 23, 2009 · 3 comments
Closed

Recursive module types #4899

vicuna opened this issue Oct 23, 2009 · 3 comments
Assignees

Comments

@vicuna
Copy link

vicuna commented Oct 23, 2009

Original bug ID: 4899
Reporter: marc_defalco
Assigned to: @garrigue
Status: closed (set by @garrigue on 2011-12-14T08:25:34Z)
Resolution: not a bug
Priority: normal
Severity: feature
Category: ~DO NOT USE (was: OCaml general)
Related to: #6818
Monitored by: @jberdine

Bug description

It is not possible to refer to a module type inside its definition, an Unbound_modtype error is thrown.

Additional information

In the light of first-class modules it is quite natural to want such restriction to be lifted.
For example consider the following module type :

module type TOOL = sig
type t
val process : t -> (module TOOL) option
end

allowing to define the usual pattern for tool-based widgets (the widget delegates event processing to the current tool, which returns a possible new selected tool).

@vicuna
Copy link
Author

vicuna commented Dec 14, 2011

Comment author: @gasche

It is possible to work around the lack of this feature by wrapping your signature inside a recursive module (this is actually a generic workaround for the problem "recursion between such and such structure item is not allowed"):

module rec Tool : sig
module type S = sig
type t
val default_event : unit -> t
val process : t -> (module Tool.S) option
end
end = struct
module type S = sig
type t
val default_event : unit -> t
val process : t -> (module Tool.S) option
end
end

The downside is that you have to repeat the signature in the recursive module signature and implementation (recursive module must have a signature). Otherwise, it works relatively well:

module rec OddTool : Tool.S = struct
type t = unit
let default_event () = ()
let process () =
print_endline "Odd"; Some (module EvenTool : Tool.S)
end
and EvenTool : Tool.S = struct
type t = unit
let default_event () = ()
let process () =
print_endline "Even"; Some (module OddTool : Tool.S)
end

let test =
match EvenTool.process (EvenTool.default_event ()) with
| None -> assert false
| Some o ->
let module O = (val o : Tool.S) in
O.process (O.default_event ())
;;
(*
Even
Odd
*)

One issue I quickly ran into while experimenting on this is that recursion is closed, and you may have wished it to be open. You can weaken the global signature with "with type = ..." equations, but this won't apply to recursive occurrences of the module type, making it useless.

module rec OddTool : Tool.S with type t = unit = struct
type t = unit
let default_event () = ()
let process () =
print_endline "Odd"; Some (module EvenTool : Tool.S)
end
and EvenTool : Tool.S with type t = unit = struct
type t = unit
let default_event () = ()
let process () =
print_endline "Even"; Some (module OddTool : Tool.S)
end

match EvenTool.process () with
| None -> assert false
| Some o ->
let module O = (val o : Tool.S) in
O.process ()
(* ^^
Error: This expression has type unit
but an expression was expected of type O.t *)

I don't know how to work around this.

@vicuna
Copy link
Author

vicuna commented Dec 14, 2011

Comment author: @garrigue

Just as a complement to gasche's note, there is actually no need to duplicate the module type definition. If a recursive module contains only type definitions, the body can be omitted.

module rec Tool : sig
module type S = sig
type t
val default_event : unit -> t
val process : t -> (module Tool.S) option
end
end = Tool

This is a standard technique.
You cannot expect module type to become recursive because this would not be backward compatible, but the above trick should be sufficient in practice.

@vicuna
Copy link
Author

vicuna commented Dec 14, 2011

Comment author: @garrigue

The description was a bit misleading.
What you get is not an exception (bug in the compiler) but a legitimate type error.
Since there is a reasonable workaround, and modifying the current behaviour would not be backward compatible, better to do nothing.

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