[ocaml-platform] on the need and design of OCaml namespaces

Alain Frisch alain.frisch at lexifi.com
Fri Feb 22 17:22:44 GMT 2013


On 2/22/2013 3:06 PM, Leo White wrote:
> There are a number of possible solutions to spurious opens. The simplest
> of which is to only look for "Core.Std.Mutex" in directories which
> contain the special "Core.Std" .cmi file (mentioned previously as a
> solution to typos in open statements). These special .cmi files could
> also be extended to include a list of modules that have that namespace
> within the current directory which would prevent spurious reads entirely.

This seems a little bit hackish to me, and likely to require more 
over-engineering (do we need a tool to create those .cmi files; if they 
are plain text file, it's ugly to use the .cmi extension).

>>  - It prevents from putting .cmi files from many libraries in the same
>> directory, which is sometimes useful (to simplify deployment; to
>> control precisely the set of .cmi available for a given file; to
>> improve performance by avoiding repeated lookups in many directories).
>
> I think that this ability is of dubious value and not really a big loss.

We use this quite intensively on LexiFi's code base.  This really speeds 
up compilation time under Windows, and we also use it to simplify 
deployment (our application is shipped with some .cmi files from many 
libraries and automatically compiles user-provided addins against them; 
it would be tedious -- and useless -- to reproduce a complete hierarchy 
of libraries on the installation side).

We would hate to have the third-party libraries we use adopt a new 
feature (namespaces) which solves a problem we don't have but forces us 
to change in non trivial ways how we organize our code base and deployment.

> This is basically an error, so dependencies
> should not be expected to be correct.

I don't agree.  Having wrong dependencies is a nightmare to debug and 
during development having errors in the code is not an exceptional 
situation.  A robust build system should handle nicely things like 
moving files around, renaming them, etc.

> There is possibly the need for some kind of partial dependency for
> parallel builds. This is more like a lock than a dependency, so there
> should be no question of circular dependencies. I'm not really familiar
> with how parallel file accesses work on different file systems, but
> perhaps the compiler could lock ".cmi" files before reading and writing.
> This might be a good idea more generally for cases where dependencies
> have not been correctly calculated.

These locks do not really solve the problem.  Imagine you have a big 
project with two modules

   foo/a.ml in namespace Foo
   bar/a.ml in namespace Bar

Now you compile x.ml which refers to Foo # A. "ocamldep -modules" 
reports that the dependencies for it include mode "A", which must be 
mapped to all buildable a.cmi/a.cmx in your tree, i.e. both foo/a and 
bar/a.  (Things are even worse if you use the same syntax as for 
modules, because then any reference like Foo.A must be interpreted as a 
potential dependency to foo.cmi/cmx or to a.cmi/cmx.)  But maybe 
bar/a.ml refers to x.ml, and then you have a circular dependency.

I'd like any proposal about namespaces to come with a description of (i) 
how ocamldep is supposed to behave; (ii) how build systems (based on, 
say, make, omake and ocamlbuild) are supposed to be adapted.

So here it is for my proposal of using "short names" declared in 
external files:

   - Doing "open namespace Core_std" is strictly equivalent to doing 
"module Mutex == Core_std_mutex;; module Thread == Core_std_thread;; 
module Date == Core_std_date" assuming a new module aliasing feature 
(available in structures and signatures).

   - ocamldep would read the core_std.ns file (meaning that it must 
exist and be up-to-date when ocamldep runs; I expect those files to be 
quite static so this shouldn't be a big problem -- otherwise, we would 
need to have a first pass where ocamldep would returns the list of .ns 
files to be opened, and the build system would arrange to build them).

  - when ocamldep encounters a module reference "Mutex" in a scope where 
an alias "module Mutex == Core_std_mutex" has been defined (manually or 
by loading core_std.ns), it reports a dependency to module 
Core_std_mutex instead of Mutex.

  - the build systems do not have to be adapted.



>
>> That's why I've proposed to allow specifying mapping between
>> references to external modules in dedicated files.  We could have a
>> file core_std.ns (probably shipped with Core) with this content:
>>
>> Mutex = Core_std_mutex
>> Thread = Core_std_thread
>> Date = Core_std_date
>>
>> and just a reference in the source code (or on the command-line):
>>
>>   open namespace Core_std
>>
>> which would load core_std.ns and use the corresponding module renaming
>> in the rest of the module.
>
> There is very little difference between that suggestion and having a
> core_std.ns file containing:
>
>   Mutex;
>   Thread;
>   Date;
>
> and using that as a (partial) declaration of a Core_std namespaces,
> except that you have to give every file a unique long filename. So I
> don't really see the particular benefit of using long filenames.

With my proposal, you don't force users of the library to use the new 
feature (meaning that if for some reason your local build system does 
not work nicely with namespaces, you can always refer to modules using 
their long names).  Moreover, the semantics is very easy to explain, the 
linker does not need to be changed, and we don't change how OCaml 
behaves w.r.t. to the file system (your proposal prevents users from 
using the currently valid technique of copying .cmi files from many 
libraries in the same directory).

> There is also a more general problem with any solution like this, which
> tries to define namespaces (or sets of aliases) in a single file. It is
> difficult to use the namespace from inside the modules that are within
> the namespace. For example, if I use:
>
>   open namespace Core_std
>
> from within mutex.ml then it will attempt to open itself.


I don't understand the problem.  The source file would be 
core_std_mutex.ml and it is fine if it does "open namespace Core_std" as 
long as it doesn't refer to Mutex (which would be a circular dependency).


Alain


More information about the Platform mailing list