4 ms·
Well, that comes with a few caveats: 1. OCaml generates additional information that it stores in .cmi/.cmx files. 2. OCaml does not allow for mutual dependenc
by rbehrends 9y ago
Well, that comes with a few caveats:
1. OCaml generates additional information that it stores in .cmi/.cmx files.
2. OCaml does not allow for mutual dependencies between modules, even in the linking stage. Object files must be provided in topologically sorted order to the linker.
3. OCaml supports shared generics, which cuts down on the amount of code replication (at the expense of requiring additional boxing and tagged integers in order to have a uniform data representation).
- rwmj 9y agoAll true except #3 (partially). > 1. OCaml generates additional information that it stores in .cmi/.cmx files. On this point I'd say that it could probably embed the cmx file as "NOTE" sections in the ELF object files, but likely they didn't do it that way because it's easier to make it work cross-platform. Every "pre-compiled header" system I've seen generates some kind of extra file of compiled data which you have to manage, so I don't think this is a roadblock. > 2. OCaml does not allow for mutual dependencies between modules, even in the linking stage. Object files must be provided in topologically sorted order to the linker. I believe this is to do with the language rather than to do with modules? For safety reasons, OCaml doesn't allow uninitialized data to exist. Although (and I say this as someone who likes OCaml) it does sometimes produce contortions where you have to split a natural module in order to satisfy the dependency requirement. I've long said that OCaml needs a better system for hierarchical modules and hiding submodules (better than functors, which are obscure for most programmers). > 3. [...] at the expense of requiring additional boxing and tagged integers [...] I think this is fixed by OCaml GADTs: https://blogs.janestreet.com/why-gadts-matter-for-performance/ https://blogs.janestreet.com/why-gadts-matter-for-performanc... However this is a new feature and maybe not everyone is using it so #3 is still a fair point.
- rbehrends 9y ago> I believe this is to do with the language rather than to do with modules? Both, sort of. The problem is that mutually recursive modules are tricky. So, it's a limitation of the language, but one that is there for a reason. > I think this is fixed by OCaml GADTs No, GADTs solve a different problem. Essentially, normal ADTs lose type information (due to runtime polymorphism). GADTs give you compile time polymorphism, so the compiler can track which variant a given expression uses. Consider this: # type t = Int of int | String of string;; type t = Int of int | String of string # [ Int 1; String "x" ];; - : t list = [Int 1; String "x"] # type _ t = Int: int -> int t | String: string -> string t;; type _ t = Int : int -> int t | String : string -> string t # [ Int 1; String "x" ];; Error: This expression has type string t but an expression was expected of type int t Type string is not compatible with type int The problem with functors (and also type parameters) is the following. Assume that you have a functor such as: module F(S: sig type t val f: t -> t end) = struct ... end To avoid code duplication, F has to pass arguments to S.f using the same stack layout, regardless of whether it's (say) a float, an int, or a list. This means that floats need to get boxed (so that they use the same memory layout) and integers have to be tagged (because the GC can't tell from the stack frame what the type of the value is).