On Fri, Jun 4, 2010 at 9:48 PM, Kris Kowal <kris.kowal at cixar.com> wrote:
> 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.
In your example, certainly the earlier error is a benefit of our
proposal. But the really key benefit is this:
module M {
export x = 7;
}
module N {
M.y + 3; // an error - just like an unbound variable in ES5 strict
}
This can be an early error because we statically know a lot about
modules. This is good for programmers, because it supports early
errors, and also good for compiler writers, since it supports
optimization.
>> 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.
Because Simple Modules is based on lexical scope, collecting modules
is as simple as collecting objects into a larger object:
module Container {
module Sub1 = load "http://example.com/foo.js";
module Sub2 = Other.InnerModule;
module Sub3 {
module SubSub4 = load "http://example.org/bar.js";
}
}
>> 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.
Currently, in web-based IDEs such as Bespin, code being developed has
the ability to muck with the internal state of the IDE and the overall
page, which is usually undesirable. With module loaders, simply by
not sharing access to the DOM or other internal state with the code
being developed, this would be prevented.
>>> 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?
Yes, if that URL has a module Y in the code that it provides. For
example, if that URL produces the code:
module Y { ... }
module Z { ... }
Then it's certainly possible.
> Is it possible for MRL's to be CommonJS top-level and relative module
> identifiers?
We've avoided committing to particular syntax for MRLs so far,
although the discussion at the last meeting tended toward the
following syntax:
MRL = URL | RelativeURL | "@"Identifier
with the last case for modules provided by the host environment.
> 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("/"));
> }
> })
This could work, certainly. Note that there's no particular need for
the externalLoaders to be ModuleLoaders themselves - they could have
whatever API is useful in this context.
> 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.
This is one thing we've resolutely tried to avoid. A key aspect of
our module system is that it gets sharing right - if you import a
module in two different places, that module is shared. This requires
knowing when you import "the same" module. In most languages, this
ultimately comes down to some filesystem-based comparison, which we
don't have the luxury of on the web. MRLs don't support a very good
equality operation. That's why we've gone simply with names, with a
very simple equality.
--
sam th
samth at ccs.neu.edu