> It would be
> good for this to be expressed in one of the examples, and
> for it to be clarified in the description of semantics that
> every script is also an anonymous module from which the
> exports are only accessible through the lexical scope
> "shadowing" (I assume) and by being bound to a module
> through a "load" expression.

This doesn't sound quite right-- in the terminology we used, scripts are not 
modules. An application is composed of a sequence scripts, which are like 
module bodies but do not contain exports. Each script's bindings are in scope 
for all subsequent scripts. By contrast, the target of "load" is the body of a 
module, which can export bindings.

> This is a point that Ihab clarified for me yesterday
> evening that merits bold and emphasis: loaded modules are
> not singletons.

Yes, I think something we need to do is write out some more material explaining 
the proposal in more tutorial fashion. The examples page was a start, but 
clearly not enough.

> You do this to avoid having to compare
> MRL's for equivalence, particularly to avoid having to
> define equivalence given the potential abundance of edge
> cases.
> 
>    http://example.com/module?a=10&b=20
>    http://example.com/module?b=20&a=10

Yes, as well as the fact that even the bit-for-bit same URL can deliver 
different bits from moment to moment. So module loading really is effectful 
(albeit at compile time), in the sense that it performs arbitrary Internet I/O. 
In lieu of requiring programmers to learn rules about when two references to 
modules are referring to the same memoized instance and when the instance is 
loaded and evaluated, simple modules make all this explicit and under the 
programmer's control.

> It would also be good for there to be a way to bind $ without binding
> a module.
> 
>    const A = load("aQuery.js").$;
>    const B = load("bQuery.js").$;

There are a couple reasons why I think I'd avoid this kind of thing: for one, 
it means that |load| -- which indicates a /compile-time/ operation -- can now 
be arbitrarily nested in a program instead of just at top level. Also, loading 
is a fairly heavyweight operation, and since it doesn't memoize, you could very 
easily end up with accidental duplication.

As Sam says, you can write almost the same thing via dynamic loading:

    const A = ModuleLoader.current.loadModule("aQuery.js").$;
    const B = ModuleLoader.current.loadModule("bQuery.js").$;

or a little more conveniently:

    function load(ml, mrl) {
        return ml.loadModule(mrl);
    }

    const ml = ModuleLoader.current;

    const A = load(ml, "aQuery.js").$;
    const B = load(ml, "bQuery.js").$;

The main difference from what I think you intended is that this would do the 
loading dynamically.

>> It's possible to use the module loader API to do this,
>> slightly more verbosely.   But why?  If you say:
>> 
>> module A = load "aQuery.js";
>> 
>> then A.$ is already available for use in expression
>> contexts.
> 
> I can make the same argument about "import *".  If I "import
> A", I can access its contents as "A.$".  To permit
> destructing on all import expressions would be consistent
> philosophically.

I don't follow your reasoning-- import A.* is a convenience form to bind the 
exports of A as local variables. It serves a very different purpose.

Local, nested module loading could either mean static loading, which I contend 
would be confusing and error-prone, or dynamic loading, which is already 
available via the dynamic loading API.

>> Your example might point to a need to augment the module
>> loader api with information on 'load' calls specifying
>> what module the 'load' occurs in.
> 
> Exactly.  The Narwhal loader receives an id and a baseId on
> from require(id) calls.  Each module gets a fresh "require"
> effectively bound on the baseId.  I think that the loader
> handler needs to receive the base MRL as an argument or part
> of the request object.

Yes, I agree. That was an oversight-- thanks for bringing it up.

> Another thing that Ihab clarified which merits a full
> section on the wiki is the dynamic scoping of lexical module
> names.

I've said it before: it's not dynamic scoping. It's static, lexical, 
compile-time scoping. Dynamic scoping necessarily involves dynamically 
determining the binding of a variable. There's nothing of the sort happening 
here; it's all compile-time.

> This is something I have not considered.  It would be good
> to do a write-up on what use-cases you have in mind for this
> feature.

Yes, we should definitely do that. Two important use cases are 1) standard 
libraries, which would be shared as global module bindings in a standard module 
loader, and 2) mutually recursive modules, which need to agree on what they 
call one another.

> I'm going to mull the implications, but one for
> sure, is that it is necessary to buy a whole package even if
> you only want a single function from it.

True. I don't think it's reasonable to try to solve the more intricate problems 
of partial or on-demand loading of modules. I think people are still 
experimenting with this in the wild, and IMO it's premature to try to solve 
this in Harmony. With dynamic loading, people can continue experimenting with 
different approaches. And especially when you consider the fact that on-demand 
loading means the semantics is doing network I/O behind your back and lazy 
evaluation of arbitrary JS code, it becomes a very difficult programming model. 
As I've said before, laziness and effects don't mix (ask any Haskellite! ;).

> * load handlers need to receive the MRL of the declaring
>  module so they can resolve relative MRLs.  This one's
>  important.

Agreed.

> * there should be cleaner syntax for destructuring a loaded
>  module.  Preferably whether a module is rebound or loaded
>  should be orthogonal to the destructuring syntax.  Sugar.

I'm not sure I know what you're looking for here.

> * the community should be called upon to weigh in on whether
>  "import *" should be supported, and we should frame the
>  question with education on the full implications of the
>  trade-off.

A few thoughts:

1. I'd rather have a module system without import A.* then no module system at 
all.

2. Community discussion of the issue is, of course, fine -- that's what 
es-discuss is here for.

3. IMO, it'd be a big mistake to eliminate import A.*. It's not hard to avoid 
it, proscribe it in coding standards, or even reject it from lint tools. But 
withholding it from the language eliminates a real convenience for simple 
scripting, which continues to be an important use case for ES. And I don't see 
the proscription providing enough value.

The hazard of import A.* is that a new version of A may introduce new bindings 
that conflict with another module's bindings. In that case, code in the wild 
will start failing because it gets a compile-time conflict that isn't resolved. 
Another cost is that people would be more likely to use import A.* when A is 
some widely used library (including the builtins). This adds /some/ pressure 
for library writers to be more conservative about introducing new bindings.

But the failure mode for all of these is an early, compile-time error; in 
practice, production systems would pin particular versions of libraries rather 
than downloading from a 3rd-party server; and generally production systems 
would probably avoid it anyway. And that's not what it's there for. It's there 
for quick scripts, rapid prototyping, etc.

> * we should consider a way to link one loader to another,
>  such that a loader, for example a package loader, can be
>  mapped responsibility for all modules in a subtree of the
>  MRL name space without having to communicate exclusively
>  in source strings.

IIUC, this might already be achievable with the load hook (the function passed 
to the ModuleLoader constructor). The latter can make whatever decisions it 
wants about how to handle any given MRL. And it avoids having to over-specify 
MRL's. (We may end up needing to specify more of MRL's anyway, but I'd prefer 
to do no more than necessary.)

Dave

_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to