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

Yaron Minsky yminsky at janestreet.com
Tue Feb 26 22:36:06 GMT 2013


On Tue, Feb 26, 2013 at 5:03 PM, Didier Remy <Didier.Remy at inria.fr> wrote:
> Yaron,
>
>>> Do you really need this level of granularity?  I'd like to think of
>>> modules as the smallest compilation unit.  Can you give us examples of
>>> what
>>> you'd like to do with value manipulation?
>>
>>
>> I think we do.  What we want is essentially the same thing that we
>> need to do when OCaml opens Pervasives by default.  We simply have
>> another module that we wish to open by default.
>
>
> This is quite different than cherry-picking values from a module.  Also open
> is a bit misleading here, because it must behaves like an include.  While
> open brings all subcomponents in scope but does not evaluate them, include
> must evaluate (use) all the definitions and binds them in the current
> structure.

Perhaps I'm just out of my depth here, but I don't really see the
issue.  In Alain's world, you could imagine that a namespace mechanism
definition combines two things: a list of name-remappings, and a list
of names to open.  I would then think that the declaration:

    open namespace Foo

would essentially expand to something like:

    module alias A = Foo_a
    module alias B = Foo_b
    module alias C = Foo_c
    module alias Common = Foo_common
    open Foo_common

and that's that.

> This is quite different from what happens when building namespaces: when a
> new definition shadows an older one in a namespace, the older definition
> will not be visible by the linker and will not be evaluated.
>
> "Include-on-open" (called flat-acccess by Gabriel) is doable as Gabriel
> explained, and would generalize the behavior of pervasives, but it is
> another mechanism than just building a namespace (because it also _uses_ a
> module).

I agree that this essentiall combines together two features into one.
Maybe the difference is that I view this as more feature than bug.

>> There are two reasons for this: the first is to open at the top-level
>> some constructors and values that are very commonly useful.  Much as
>> pervasives has None and Some from option available everywhere, we have
>> Ok and Error from Result.t available everywhere.
>
>
> Fine.
>
>
>> Another reason is to shadow values from other modules.  Core.Std hides
>> various values from Pervasives that we view as harmful.  For example,
>> we hide ==, and instead expose phys_equal.  (We think == is too
>> confusing to people from other languages.)
>
>
> This example is different I think, and perhaps another solution
> could be used.  My understanding is that you wish to have your own
> version of stdlib, say stdlib_minus_plus.
>
> Why don't you create a new module stdlib_minus_plus that includes stdlib
> with a restricted safe interface (so that bindings "minus" will be evaluated
> but not visible) and then add your own safer definitions "plus", bind the
> resulting module to some namespace Core#stdlib and then use your own version
> of Core#stdlib instead of the original stdlib?
>
> It seems that you wish Core.std to be only a diff against the original
> stdlib and not a patched copy. Is this the case? Why it is important?
>
>> Similarly, Async hides blocking operations that are available in
>> Core.Std, like print_string, so when you write:
>>
>>     open Core.Std
>>     open Async.Std
>>
>> those problematic values are hidden from.
>
>
> Isn't this fragile? for example, what happens if the user mistakenly writes
> these two lines in the other order? If Async.Std _must_ hide values of
> Core.Std for safety reasons (for instance to avoid blocking), why is it not
> returning a patched copy of Core.Std with these values overridden instead of
> relying on the user to open modules in the right order?

It is somewhat fragile, but it's reasonably workable, and it allows
you to carefully reach into Core.Std to get unsafe values when you
want to (which you do sometimes want to do).

To be clear, if there was a good mechanism for punching holes in
Core.Std and exporting that, we might be quite happy to do that.  We
just don't have a clean mechanism for doing so in the present world.

>> think, to make every single file that uses Core have to change from:
>>
>>     open Core.Std
>> to
>>     open namespace Core.Std
>>     open Core.Std.Common
>>
>> or whatever it would need to be.
>
>
> I don't see what you mean here.

I merely mean that, in practice, users of Core need to open
Core.Std.Common.  If we don't allow the namespace operation to do it
for them, then users will need to type both lines every time.  This
seems error prone, especially for new users.

Indeed, if we had this, we might just write a ppx extension that gave
us the one-line declaration we want.

y


More information about the Platform mailing list