A.) LOAD(..., function(a, b, c) { ... });
B.) LOAD(..., function() { require("a"); require("b"); require("c"); }
C.) LOAD(..., function(require, exports, module) { require("a"); }
Current show of hands. Please copy and alter in your responses.
A.)
B.) Christoph Dorn
C.) Christoph Dorn, Kris Kowal
Christoph Dorn on B or C: "This is most consistent with Modules/1.1
and represents the intended behavior where once LOAD() has satisfied
loading the modules they are available to the current sandbox just
like any other module."
Kris Kowal on C: This would permit the availability of modules to be
enforced on the inner block, given what working sets have been
explicitly required. This was one outcome of the discussion with Wes
Garland on require.ensure, and I think it fits here.
Kris Kowal
Lazy loading is accommodated by both options A and C. B does not
because it is not possible to statically distinguish the require calls
inside the callback from those outside, which is the point you appear
to address here. Note that C does not necessarily have this weakness.
> The zero argument form is ok and deals with the case where you have a
> lot of dependencies. I don't understand why you'd want the three
> argument form.
This form permits a different require function to be provided in the
inner and outer scope which would enforce the contents of the working
set in the inner and outer scopes. If the LOAD call augments an
existing working set of modules, it is possible for there to be an
unnoticed race condition if "require" is called outside the scope of
the LOAD callback for a module that was loaded by the LOAD call.
While it is not necessary to separate the working sets of the inner
and outer require calls in case C, it is at least possible to turn the
race condition into an early error, by having the outer require object
refuse to provide modules from the extended working set.
I am opposed to option B because it would preclude using this API for
lazy loading. I could be convinced to switch to A from C, but I've
written too many modules where C would be far more desirable than A
because of the quantity of bindings.
No changes:
A.) +1 James Burke
exports and module in particular do not make sense in that function
callback. The require from the containing scope can be used inside the
callback, so that is why I do not prefer C.). It is too much typing to
have to re-type the dependency name with require() as indicated in B).
James
This is a critical point. The objective of LOAD() is to provide a
boundary between the current program and a set of optionally loaded modules.
Static analysis / require() scraping must stop at the LOAD() boundary.
It follows that the boundary must be detectable. I see two solutions:
1) Disallow require() within LOAD()
2) Make LOAD() predictably parsable
(1) applies sensibly only to option (A).
(2) could work with all three but unreliable. I thus suggest to drop
inner require() calls completely.
Updated options:
A.) LOAD(..., function(a, b, c) { ... });
B.) LOAD(..., function() { require("a"); require("b"); require("c"); }
C.) LOAD(..., function(require, exports, module) { require("a"); }
E.) LOAD(..., function(a, b, c) { ... }); - no internal require()
I change my vote to (E). Argument:
(E) is the most robust solution by not allowing require() calls within
LOAD() as it puts the responsibility on the developer vs static analysis
trickery. LOAD()ing extra code this way is designed to load *bootstrap*
modules into a sandbox where the bootstrap module should require()
dependencies vs a bunch of dependencies given to LOAD().
When writing CommonJS programs code belongs into one module per file.
Period. Providing any facility that seemingly makes magic module scopes
available (B, C) is misleading. I think we are better off declaring that
the factory/callback of LOAD() is simply a callback that triggers when
[deps] are met with module references provided if desired.
A.) John J Barton, Jame Burke
B.) Mikeal Rogers
C.) Kris Kowal
E.) Christoph Dorn
Christoph
Assuming that the outer module is not wrapped, it is necessary to
scrape the content for require() calls, which are not distinguishable
between the inner and outer scopes. Assuming that the outer module is
wrapped, which you appear to assume, you are right that form B does
not preclude lazy loading. We should probably clarify that.
We also know that A and C are mutually exclusive. A+B, B+C are not.
A.) John J Barton, Jame Burke
B.1.) Christoph Dorn, Mikeal Rogers, John J Barton, assuming that
modules are necessarily wrapped with a "define" call
B.2.) Christoph Dorn, Mikeal Rogers, assuming that modules are not
necessarily wrapped with a "define" call
C.) Christoph Dorn, Kris Kowal
Kris Kowal
I think that enough has been clarified that others might reconsider their votes.
A.) LOAD(..., function (...modules) { require permitted })
B.1.) LOAD(..., function () { require permitted } necessarily wrapped
B.2.) LOAD(..., function () { require permitted } not necessarily wrapped
C.) LOAD(..., function (require, exports, module) { require permitted )
D.) ?
E.) LOAD(..., function (...modules) { require not permitted })
A.) John J Barton, Jame Burke, Kris Kowal
B.1.) Mikeal Rogers, John J Barton
B.2.) Mikeal Rogers
C.) No-one
D.) No-one
E.) Christoph Dorn
Updating my vote based on Kris K's interpretation.
A.) John J Barton, Jame Burke, Kris Kowal, Christoph Dorn
B.1.) Mikeal Rogers, John J Barton
B.2.) Mikeal Rogers
C.) No-one
D.) No-one
E.) No-one
Christoph
In the comedy business, I think they call that a soft-ball. The
implication that E is "Profit" was not missed, which compelled ne to
vote for on that reason alone, but thought better of A.
Re-clarification for scanners:
A.) LOAD(..., function (...modules) { })
require is permitted inside the function block, but is only guaranteed
to be able to return the exports of the working set of the
containing module.
B.1.) LOAD(..., function () {}
where the containing module is necessarily wrapped with something
like a DECLARE block
(pending a decision on whether LOAD and DECLARE are equivalent)
B.2.) LOAD(..., function () {})
where the containing module is not necessarily wrapped with DECLARE, meaning
that require calls must be scraped for dependencies, such that require calls
both inside and outside the load block are effectively static dependencies
C.) LOAD(..., function (require, exports, module) {})
where the outer require is only guaranteed to be able to return the exports
of the working set of the containing module, and the inner require
is guaranteed
to be able to return the exports of the working sets of all
mentioned modules
and the parent module.
Hands:
A.) John J Barton, Jame Burke, Kris Kowal, Christoph Dorn
B.1.) Mikeal Rogers, John J Barton
B.2.) Mikeal Rogers
C.) No-one
I've redacted D and E since their champion has withdrawn.
Kris Kowal
Question though: should this be guaranteed to work?
LOAD("a", function() {
var a = require("a");
});
since by the time the callback is executed "a" is guaranteed to be loaded?
Granted it's more verbose, but is there any reason it wouldn't technically work?
> A.) John J Barton, Jame Burke, Kris Kowal, Christoph Dorn, Tom Robinson
> B.1.) Mikeal Rogers, John J Barton
> B.2.) Mikeal Rogers
> C.) No-one
>
> I've redacted D and E since their champion has withdrawn.
>
> Kris Kowal
>
> --
> You received this message because you are subscribed to the Google Groups "CommonJS" group.
> To post to this group, send email to comm...@googlegroups.com.
> To unsubscribe from this group, send email to commonjs+u...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/commonjs?hl=en.
>
In this case, "a" becomes a static dependency of the containing
module, so the LOAD call becomes superfluous and "a" is not loaded
lazily. I had a thought that a loader might be written to prevent a
race-condition by denying the load of "a", but the mechanism is far
too convoluted to even bother working around. Let's drop the caveat to
A.
Kris Kowal
A.
Kris Kowal
If a module loader still wants to implement automatic require()
scraping, it can simply look for instances of LOAD() before starting
to scan for require() calls, and abort scraping if there are any.
On that background, my vote is for B:
LOAD(..., function() { require("a"); require("b"); require("c"); }
In case require wasn't available already outside the callback, a B/C
hybrid could make sense (as James noted, there's no use for passing
exports/module in LOAD callback):
LOAD(..., function(require) { require("a"); require("b"); require("c"); }
Hannes
2011/1/27 Kris Kowal <kris....@cixar.com>:
The proposition is that require and LOAD serve two different
purposes: require is for specifying static dependencies. It is a
"psuedo"-keyword and suitable for static analysis (ie "scaping").
LOAD is for dynamic module loading. This is when you want to load a
module but you don't know what it will be until runtime.
--
LOAD() is designed to be combined with require scraping to *load*
additional sets of modules into the current program that should
expressly not be included in the initial program arrived at via require
scraping (or following require()s in a sync environment).
Christoph
No - think of this LOAD as analogous to the Module Loaders API
proposal for Harmony. It's a way to load modules (not "dependencies")
at runtime, when you may not know the identity of the module you want
to load, until runtime.
Correct. It's a way to async load an extra module set into a sandbox
seeded by one or more module IDs passed to LOAD that are resolved in the
same fashion as IDs passed to require() within the same module.
Christoph
Hands:
A.) John J Barton, Jame Burke, Kris Kowal, Christoph Dorn, Tom Robinson
B.1.) Mikeal Rogers, John J Barton
B.2.) Mikeal Rogers
C.) No-one
D.) Irakli Gozalishvili