| Anonymous | Login | Signup for a new account | 2013-06-19 06:42 CEST | ![]() |
| Main | My View | View Issues | Change Log | Roadmap |
| View Issue Details [ Jump to Notes ] | [ Issue History ] [ Print ] | ||||||||||
| ID | Project | Category | View Status | Date Submitted | Last Update | ||||||
| 0002629 | OCaml | OCaml general | public | 2004-06-01 01:23 | 2004-06-20 17:07 | ||||||
| Reporter | administrator | ||||||||||
| Assigned To | |||||||||||
| Priority | normal | Severity | feature | Reproducibility | always | ||||||
| Status | acknowledged | Resolution | open | ||||||||
| Platform | OS | OS Version | |||||||||
| Product Version | |||||||||||
| Target Version | Fixed in Version | ||||||||||
| Summary | 0002629: Recursive modules - awkward dynamic semantics | ||||||||||
| Description | Hi, there is a very confusing issue concerning the dynamic semantics of recursive modules. Please consider the following code: --------------------------------------------------------------------------- module type S = sig val f : unit -> unit val g : unit -> unit end module MakeA (X : S) = struct let g = X.f let f () = print_endline "f" end module MakeB (X : S) = struct include X end module rec A : S = MakeA (B) and B : S = MakeB (A) let () = B.g () --------------------------------------------------------------------------- The above code will fail with an exception "Undefined_recursive_module", but IMHO it should print "f". Eta-expanding the definition of "g" in "MakeA" solves the problem. This seems a little bit awkward to me. I think that this should be handled transparently, i.e. that intermediate bindings are also updated when the recursive definition is completely evaluated rather than letting them point to the dummy function that throws an exception. What do you think, could this be fixed? Best regards, Markus -- Markus Mottl http://www.oefai.at/~markus [^] markus@oefai.at | ||||||||||
| Tags | No tags attached. | ||||||||||
| Attached Files | |||||||||||
Notes |
|
|
(0000219) administrator (administrator) 2004-06-20 17:06 |
Dear Markus, > there is a very confusing issue concerning the dynamic semantics of > recursive modules. Please consider the following code: > > --------------------------------------------------------------------------- > module type S = sig > val f : unit -> unit > val g : unit -> unit > end > > module MakeA (X : S) = struct > let g = X.f > let f () = print_endline "f" > end > > module MakeB (X : S) = struct > include X > end > > module rec A : S = MakeA (B) > and B : S = MakeB (A) > > let () = B.g () > --------------------------------------------------------------------------- > > The above code will fail with an exception "Undefined_recursive_module", > but IMHO it should print "f". > Eta-expanding the definition of "g" in "MakeA" solves the problem. This is consistent with the operational interpretation of "module rec" outlined in the reference manual: initialize A and B with default functions that raise Undefined_recursive_module, compute the functor applications, then update A and B. The eta-expansion is indeed necessary to ensure that the reference to B.f in MakeA does not evaluate to the default function. > This seems a little bit awkward to me. I think that this should be > handled transparently, i.e. that intermediate bindings are also updated > when the recursive definition is completely evaluated rather than letting > them point to the dummy function that throws an exception. I see no way to do this while remaining in a call-by-value semantics. What I plan to do at some point in the future is to implement a compile-time analysis of "module rec" definitions that will signal an error on examples such as yours. Best regards, - Xavier Leroy |
|
(0000220) administrator (administrator) 2004-06-20 17:07 |
Feature wish: compile-time detection of ill-founded "module rec" |
|
(0000221) administrator (administrator) 2004-06-20 17:52 |
Dear Xavier, On Sun, 20 Jun 2004, Xavier Leroy wrote: > This is consistent with the operational interpretation of "module rec" > outlined in the reference manual: initialize A and B with default > functions that raise Undefined_recursive_module, compute the functor > applications, then update A and B. The eta-expansion is indeed > necessary to ensure that the reference to B.f in MakeA does not > evaluate to the default function. Well, it's certainly in accordance with the specification, but since the dynamic semantics of recursive modules is still experimental, I thought it might be interesting to consider alternatives to the current implementation. > I see no way to do this while remaining in a call-by-value semantics. > What I plan to do at some point in the future is to implement a > compile-time analysis of "module rec" definitions that will signal an > error on examples such as yours. It might be possible to use indirections for function values, but this would probably require too many changes in the runtime and lead to heavy performance penalties with function calls. One workaround I had tried was to call a dummy-functor with the recursive module. This functor just eta-expanded all definitions, and it's result was included in the recursive module. If I remember correctly (?), this actually seemed to work to some extent before bug 0002639 (module thinning) was fixed. Now I have to eta-expand all function definitions by hand in each recursive module implementation which happens to have the same interface. This can be quite tedious. I actually wanted to use this trick ("include"ing recursive modules) to get some open recursion, i.e. one can plug in additional module layers that perform intermediate computations (e.g. logging execution of functions, etc.). Well, it seems choosing objects + inheritance, which I usually avoid when possible, would have been the better design decision... Best regards, Markus -- Markus Mottl http://www.oefai.at/~markus [^] markus@oefai.at |
Issue History |
|||
| Date Modified | Username | Field | Change |
| 2005-11-18 10:13 | administrator | New Issue | |
| Copyright © 2000 - 2011 MantisBT Group |