Composition of Uncoordinated Working Sets of Modules

Kris Kowal kris.kowal at cixar.com
Fri Jun 4 18:48:25 PDT 2010


On Fri, Jun 4, 2010 at 5:17 PM, David Herman <dherman at mozilla.com> wrote:
> By keeping modules second class, we get a number of benefits, not
> just handling cyclic dependencies. (In fact, cyclic dependencies can
> be handled nicely in a first-class module system as well.) One of
> the benefits of second-class modules is the ability to manage static
> bindings; for example, import m.*; is statically manageable. Allen
> has made some good points about how second-class modules are a good
> fit for the programmer's mental model of statically delineated
> portions of code. At any rate, cyclic dependencies are not the
> central point.

As far as I can tell, Simple Modules only changes the composition
hazard introduced by "imoprt m.*" from a run-time hazard to a
link-time hazard.

Consider the modules A, B, and C as developed without coordination
by Alice, Bob, and Charlie respectively, as Charlie updates his
version of C in the following manner:

Before:

    A.js
        import B.*;
        import C.*;
        assert.equal(foo, 10);
    B.js
        export foo = 10;
    C.js
        export bar = 20;

After:

    A.js
        import B.*;
        import C.*; // link-error that requires Alice's attention
        assert.equal(foo, 10);
    B.js
        export foo = 10;
    C.js
        export foo = 30; // change introduced by Charlie
        export bar = 20;

This being the case, I consider this neither a future nor a curse.  It
is worth noting, however, that this particular hazard has bitten me in
practice, and the CommonJS wisely omitted this feature against my
wishes, and I have not had reason to complain since.

>> The loader proposal reintroduces the idea of a "better eval", being
>> simply a hermetic evaluator that collects a working set of modules,
>> links them, and executes them.
>
> It's more than eval -- e.g., it provides load hooks to manage
> resource fetching and even allow transformation -- but yes, it does
> provide a more controlled eval.

This I had not noticed before.  I now see that the Loader constructor
accepts a handler that has an opportunity to either provide source
code, redirect, or reject a module.  This is great.  It also accepts
the global record that I proposed in as a BONUS, which is also full of
win.

> That's not true. Loaders are about isolation. I agree with you that
> conceptually, there's a level of granularity that consists of a set
> of modules, which is often what we mean by "package," at least in
> common usage (if not the particular meaning of that term in a given
> language). But the idea of nested/hierarchical modules is that
> modules scale to the large by simply making modules that consist of
> nested modules.

Perhaps you could point to or provide some sample code that
illustrates collecting modules.  My guess is that it would require a
lot of explicit linkage, rather than harnessing the hierarchy in which
the modules are organized.

> This is also not true; the ability to attach modules to module
> loaders (as well as the dynamic evaluation methods) makes it
> possible for separate module loaders to communicate. However,
> loaders aren't about linking multiple working sets, but rather
> providing isolated subspaces. (One use case I sometimes use is an
> IDE implemented in ES, that wants to run other ES programs without
> them stepping on its toes.)

Code examples would be insightful.

>> Another feature of Simple Modules is that it preserves the
>> "equivalence by concatenation" property of existing "script" tags,
>> while liberating the scripts from being sensitive to the order in
>> which they are concatenated.  This is in conflict with the goal of
>> removing autonomous module blocks.

> I don't quite understand this,

I hope that this is because I have misinterpreted the way module names
are scoped.

>> Simple Modules, at present, will not sufficiently assist people
>> constructing applications and APIs by composing non-coherent groups
>> of name spaces produced by non-cooperating groups of developers.

> The simple modules proposal explicitly *solves* the problems of
> Java-like systems where everything is hard-wired.  Instead, modules
> are given lexically scoped names, and can even be deployed without
> naming themselves; both of these features make it far easier to
> share code between different teams.

Perhaps I am misunderstanding the scope of a module name.  Is it not
true that a module is available by its self declared name in all
modules that share a loader?  Is it actually possible to bind a single
module name that provides access to all of the modules in another
loader?

    module X = load("http://example.com/api");
    module Y = X.Y; // is this possible?

Is it possible for MRL's to be CommonJS top-level and relative module
identifiers?  If that's the case, is it possible for the loader
handler to forward a request for a module to another loader?

    var externalLoaders = {};
    Loader(function (id, request) {
        var parts = id.split("/");
        if (parts[0] === "." || parts[0] === "..") {
            // what is the identifier of the module from which this
            // module was requested?  I need that to resolve the
            // identifier of the request module.
            when(fetch(id),
                request.provideSource,
                request.reject
            );
        } else {
            var external = externalLoaders[parts[0]];
            request.provideLoader(external, parts.slice(1).join("/"));
        }
    })

I think it might be best to organize the syntax around MRL's rather
than local short-names.  MRL's can be reasonably short if they're
permitted to be relative paths, which requires the module loader
handler to receive the MRL of the requesting module.

Kris Kowal


More information about the es-discuss mailing list