Module Execution Order
There seems to be some confusion here, because we've chosen the second alternative. Can you point to where you got the other impression?
There seems to be some confusion here, because we've chosen the second alternative. Can you point to where you got the other impression?
harmony:modules, under the section titled "Run-time execution":
Each externally-required module is executed the first time a module binding requires it.
which describes the execution order.
On Wed, Apr 10, 2013 at 10:25 AM, Kevin Smith <zenparsing at gmail.com> wrote:
There seems to be some confusion here, because we've chosen the second alternative. Can you point to where you got the other impression?
harmony:modules, under the section titled "Run-time execution":
Each externally-required module is executed the first time a module binding requires it.
I can see why that's potentially confusing on this issue, but the intent of that sentence is just to say that modules are executed as part of the execution of the first module that imports them. I'll see if I can come up with a better phrasing, but the spec language will obviously be much more precise.
Thanks for pointing this out,
OK, so two follow-up points:
-
Just to be explicit, this is a different execution order than node/CommonJS modules. Nothing wrong with that, just pointing it out.
-
The execution order is then just a topological sort of the dependency graph, breaking cycles where appropriate. Is that correct?
On Wed, Apr 10, 2013 at 10:36 AM, Kevin Smith <zenparsing at gmail.com> wrote:
OK, so two follow-up points:
- Just to be explicit, this is a different execution order than node/CommonJS modules. Nothing wrong with that, just pointing it out.
Yes.
- The execution order is then just a topological sort of the dependency graph, breaking cycles where appropriate. Is that correct?
Yes. Cycles are broken by reference to the order in which the relevant imports appear in the source of the importing module.
- The execution order is then just a topological sort of the dependency graph, breaking cycles where appropriate. Is that correct?
Yes. Cycles are broken by reference to the order in which the relevant imports appear in the source of the importing module.
Mmmm...
In that case, I believe we can use nested (lexical) modules for concatenation, and my previous critique doesn't hold. To bundle some root module R, we create a topological sort of R's dependencies, assign a unique identifier to each dependency, and replace occurrences of module specifier strings with the appropriate module identifier.
Does that sound right, or am I missing some point or use case?
On Wed, Apr 10, 2013 at 10:46 AM, Kevin Smith <zenparsing at gmail.com> wrote:
- The execution order is then just a topological sort of the dependency graph, breaking cycles where appropriate. Is that correct?
Yes. Cycles are broken by reference to the order in which the relevant imports appear in the source of the importing module.
Mmmm...
In that case, I believe we can use nested (lexical) modules for concatenation, and my previous critique doesn't hold. To bundle some root module R, we create a topological sort of R's dependencies, assign a unique identifier to each dependency, and replace occurrences of module specifier strings with the appropriate module identifier.
I'm not sure what prior critique you're referring to. Also, we no
longer plan to include nested modules in ES6. Also^2, concatenation
should simply require literally concatenating the modules, with
module "NAME" { ... }
wrappers with appropriate names based on the
file system (in the common case where development occurs in multiple
node-style files).
I'm not sure what prior critique you're referring to.
Quite a while ago, I pointed out that concatenation would be difficult with nested modules, but I was operating under the assumption of interleaved execution: gist.github.com/zenparsing/3892979
Also, we no longer plan to include nested modules in ES6.
Yeah, I don't like that. : ) I tend to agree with Andreas that modules should have a lexical face.
Also^2, concatenation should simply require literally concatenating the modules, with
module "NAME" { ... }
wrappers with appropriate names based on the file system (in the common case where development occurs in multiple node-style files).
But with nested modules (and topological execution order), a tool can easily create the bundle. In fact, I think it would be more effective for a tool to perform that bundling transformation than to do it by hand.
Is there any context or information that would be lost when transforming a
module "name"
module into a (hypothetical) nested module? I can't really
think of any at the moment...
On Wed, Apr 10, 2013 at 11:01 AM, Kevin Smith <zenparsing at gmail.com> wrote:
I'm not sure what prior critique you're referring to.
Quite a while ago, I pointed out that concatenation would be difficult with nested modules, but I was operating under the assumption of interleaved execution: gist.github.com/zenparsing/3892979
I think this transformation demonstrates why I prefer our current approach more than nested modules. See my fork at gist.github.com/samth/5355676
Also, we no longer plan to include nested modules in ES6.
Yeah, I don't like that. : ) I tend to agree with Andreas that modules should have a lexical face.
I don't particularly want to have this discussion yet another time, but (a) lexical modules as in our original design did not serve all the required use cases and (b) the addition in the future of lexical modules is not ruled out. Given the interest, it may be something someone wants to propose for ES7.
Also^2, concatenation should simply require literally concatenating the modules, with
module "NAME" { ... }
wrappers with appropriate names based on the file system (in the common case where development occurs in multiple node-style files).But with nested modules (and topological execution order), a tool can easily create the bundle. In fact, I think it would be more effective for a tool to perform that bundling transformation than to do it by hand.
Is there any context or information that would be lost when transforming a
module "name"
module into a (hypothetical) nested module? I can't really think of any at the moment...
I don't understand this question. A tool can perform the bundling in my gist above very easily.
- Just to be explicit, this is a different execution order than node/CommonJS modules. Nothing wrong with that, just pointing it out.
Yes.
Execute-in-order-of-import is used in practice to emulate parameterized modules (for instance, set a global config, then import RequireJS).
As long as executing a module cannot change its set of exports, only the value of exports, it should be possible to separate the binding phase (topological sorted, establish import bindings) from the execution phase.
If the execution phase is to use the same order as the binding phase, a suggested alternative to the parameterized modules pattern should be documented.
For simple parameterized modules, that would involve an exported setter, called after the imported module is executed.
For RequireJS-like uses, that would involve separate module loader phases (first phase, load RequireJS-like import; second phase, configure RequireJS and use for loading rest of dependencies).
Most likely, the classic use of modules as executable scripts should be discouraged, in favour of modules as declarative providers of bindings.
Claus
On Wed, Apr 10, 2013 at 11:39 AM, Sam Tobin-Hochstadt <samth at ccs.neu.edu>wrote:
On Wed, Apr 10, 2013 at 11:01 AM, Kevin Smith <zenparsing at gmail.com> wrote:
I'm not sure what prior critique you're referring to.
Quite a while ago, I pointed out that concatenation would be difficult with nested modules, but I was operating under the assumption of interleaved execution: gist.github.com/zenparsing/3892979
I think this transformation demonstrates why I prefer our current approach more than nested modules. See my fork at gist.github.com/samth/5355676
The correct translation using nested modules (with the proper topological execution order semantics), would be more like this: gist.github.com/zenparsing/5355927
I don't particularly want to have this discussion yet another time,
I don't remember having this discussion on es-discuss. Not that it's a requirement or anything...
but (a) lexical modules as in our original design did not serve all the required use cases
Given that bundling is possible with nested modules, I'm not sure what
other use cases module "name"
is serving. I'll look back through the use
case presentation, though.
On Wed, Apr 10, 2013 at 12:13 PM, Kevin Smith <zenparsing at gmail.com> wrote:
On Wed, Apr 10, 2013 at 11:39 AM, Sam Tobin-Hochstadt <samth at ccs.neu.edu> wrote:
On Wed, Apr 10, 2013 at 11:01 AM, Kevin Smith <zenparsing at gmail.com> wrote:
I'm not sure what prior critique you're referring to.
Quite a while ago, I pointed out that concatenation would be difficult with nested modules, but I was operating under the assumption of interleaved execution: gist.github.com/zenparsing/3892979
I think this transformation demonstrates why I prefer our current approach more than nested modules. See my fork at gist.github.com/samth/5355676
The correct translation using nested modules (with the proper topological execution order semantics), would be more like this: gist.github.com/zenparsing/5355927
I don't particularly want to have this discussion yet another time,
I don't remember having this discussion on es-discuss. Not that it's a requirement or anything...
The meeting minutes contain some rather comprehensive notes on variants of this discussion.
See rwldrn/tc39-notes/blob/master/es6/2012-11/nov-28.md#modules-update for an example.
but (a) lexical modules as in our original design did not serve all the required use cases
Given that bundling is possible with nested modules, I'm not sure what other use cases
module "name"
is serving. I'll look back through the use case presentation, though.
The most important use case not served by lexical modules is defining a module with a single name that multiple external modules can reference it with. That's the use case discussed in the above meeting notes.
If a module is lexically nested, IMO it would violate encapsulation if it could be directly named from outside that scope -- just like anything else that is lexically nested. But this goes to the core of the issues we've postponed till ES7.
The meeting minutes contain some rather comprehensive notes on variants of this discussion.
See rwldrn/tc39-notes/blob/master/es6/2012-11/nov-28.md#modules-update for an example.
Ah - I didn't understand that passage when I read through it before. Thanks for the reminder.
The most important use case not served by lexical modules is defining a module with a single name that multiple external modules can reference it with. That's the use case discussed in the above meeting notes.
I still don't understand, I'm afraid. Every external module has a URI. References to the same URI get the same module instance. The loader can define policies for URI mappings (like mapping a jquery URL to a zepto URL, for example). What am I missing?
As Kris Kowal once quipped to me a long time ago: "The only sane global name space is URL's."
On 10 April 2013 17:39, Sam Tobin-Hochstadt <samth at ccs.neu.edu> wrote:
On Wed, Apr 10, 2013 at 11:01 AM, Kevin Smith <zenparsing at gmail.com> wrote:
Yeah, I don't like that. : ) I tend to agree with Andreas that modules should have a lexical face.
I don't particularly want to have this discussion yet another time,
Well, we need to continue it soon. Maybe now is a good time?
I can't seem to remember or find the rationale behind lazy (interleaved) execution of external modules. For example:
// x.js console.log("inside x"); export var x; // y.js console.log("inside y"); import x from "x.js";
With lazy execution, loading "y.js" would produce:
The alternative would be to execute dependencies prior to executing the requested module:
What was the rationale for choosing the first alternative?