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

Török Edwin edwin+ml-ocaml at etorok.net
Wed Feb 27 17:24:12 GMT 2013


On 02/27/2013 06:31 PM, Yaron Minsky wrote:
> Let me try to summarize the current situation about the argument
> between Alain, Leo and myself.  I think Leo and I are roughly on the
> same page, but I may be missing things.
> 
> - MAKING LONG NAMES AVAILABLE.  Alain prefers to have unambiguous long
>   names that are usable in a first class way.  I find this mildly
>   distasteful, but would be OK with it as long as it was well hidden
>   from the user by default.  Long names shouldn't show up by default
>   in source files, error messages or documentation.  I view this as
>   quite important for usability of namespaces.
> 
> - SOURCE-LEVEL OPENS.  Alain would prefer to have namespace
>   manipulations restricted to the command line, and therefore the
>   build system.  He thinks of namespaces as something that should be
>   used pretty rarely (or at least, there should be very few
>   namespaces), and it's therefore OK to push them to the outside.
> 
>   Leo and I both believe this is a big mistake.  We expect opens to
>   happen fairly commonly, and for there to be many different libraries
>   that are organized as namespaces.
> 
>   Alain doubts that there would be many module-name clashes.  I
>   disagree on this point as does Leo.  We use packed modules
>   pervasively (for /every/ library), and as a result, we have lots of
>   little namespaces, and lots of repeated names within them (names
>   like Common, Protocol, Spec, Config, etc.)
> 
>   My biggest objection to having opens be at the build system level is
>   that it makes your code more ambiguous.  When you do namespace
>   manipulations, you very much want to see what's happening by
>   inspecting the source.  We have a vigorous code review system here,
>   and I don't want to start adding code review of the build rules to
>   it, and this change would require that.
> 
>   Alain's claim that opens are a bad thing also seems wrong to me.
>   opens should be rare, but all of our proposals involve the
>   equivalent of opening a namespace.  Alain is not saying we should
>   have none of that (after all, we're all glad that Pervasives is
>   opened!).  But what Alain is proposing is to make opening a
>   namespace silent at the source level.  This strikes me as a grave
>   error.
> 
> - NAMESPACES WITH VALUES.  I have argued for allowing the opening of a
>   namespace to also implicitly open some modules, this essentially
>   adding values to the search path in addition to modules.  I would be
>   sad to lose this feature, but I don't think it's absolutely
>   essential.  It would merely add boilerplate.  Roughly speaking,
>   every time a user of Core writes
> 
>      open namespace Core#Std
> 
>   instead of
> 
>      open namespace Core#Std
>      open Core#Std.Common
> 
>   they're making a mistake.  I'd like to avoid this error, and I don't
>   know really what the objection to the feature is, but in the worst
>   case, we can add a syntax extension to work around this problem,
>   using a -ppx transformer to add the open ourselves.

I'd like to add a suggestion  for the last last two requirements, from an OCaml user's perspective (i.e. not a platform/platform library implementor).
I don't feel too strongly about what the exact syntax or build system requirements are for namespaces, its just a suggestion.

core/std/common.mli:
namespace Core#Std
(* define a module Common in the Core#Std namespace.
 *  Effect: rename module to Core#Std.Common in the .cmi *)
....

core/std/common.ml:
namespace Core#Std
(* define a module Common in the Core#Std namespace.
 *  Effect: rename module to Core#Std.Common in the .cmi *)
....

Optionally one could also specify -root <path> on the cmdline to automatically create a namespace based on directory hierarchy.
If both are specified its checked that they are equal, and if not an error is shown.

core.mli:
namespace Std = struct
  module Core#Std.Common (* defines that this module is part of the namespace *)
  module Core#SomethingElse.SomeOtherModule
  open Core#Std.Common
  (* defines the Core#Std namespace in the .cmi, and the list of default opens to Core#Std.Common *)
  (* each namespace must have a .cmi named after its toplevel name
end


file_using_core.ml:
open Core#Std (* this opens the Core#Std namespace, and the Core#Std.Common module *)
(* Core#Std is of type 'namespace', so the compiler would know you open a namespace without having to explicitly say so with a keyword *)

(* you could even write *)
open Core (* opens Core namespace *)
open Std.Common (* opens Core#Std.Common module *)

namespace aliasing, and toplevel use:
> namespace Foo = Core#Std
namespace Foo = <
  module Core#Std.Common: sig .... end
  module Core#Std.SomeModule: sig .... end
   ... all modules ...
  open Core#Std.Common

How to find the module Foo#Bar.M:
 when searching for .cmi files:
   look for foo.cmi, and check namespace definitions inside
 when searching for .cmx/.cmo files (this is not optimal!):
   look for m.cmx/m.cmo, and check that full module name is good, skip to next in search path if not
 when searching for .cmxa/.cma files:
   look for a foo.cmxa/foo.cma -> defines all modules for namespace Foo.
At link time only the modules that are actually used are kept (since opening a namespace doesn't have side-effects, unused namespaces/modules can be thrown away).

Best regards,
--Edwin


More information about the Platform mailing list