Re: Module loading discussion
Jonathan Rees <[email protected]>
| Newsgroups | gmane.comp.lang.e.general |
|---|---|
| Message-ID | <[email protected]> |
I wrote a reply and put it here: http://odontomachus.wordpress.com/2009/12/03/javascript-modules/ I'm not on google-caja-discuss so did not attempt to cc: there. (maybe I should be.) Best Jonathan On Nov 19, 2009, at 9:10 PM, [email protected] wrote: > Retweeting a message from google-caja-discuss to e-lang. > > * * * * * > > Caja fans, > > A couple days ago, I presented to the Caja group some material that > I had previously presented to the ECMA TC39 committee, describing > the module system we have implemented in Caja. The slides are here: > > http://sites.google.com/site/ihabawad/Home/es5Modules-2009-11-06.pdf > > * * * * * > > At the Cajita level, we implement a module loader such that the > result of calling: > > load('foo') > > where "foo" is a module ID, returns a "module function". This is a > closed function (i.e., it has no free variables) and is instantiated > by calling it with an object literal providing bindings for its free > variables. So if "foo.js" contained, say: > > x + y; > > then the following expression: > > load('foo')({ x: 3, y: 4 }); > > would evaluate to 7. So far so good. > > One desideratum is that the IDs of modules are "self-relative". > Let's say module "a/b/c.js" contains the following expression: > > load('../d/e'); > > This should be relative to its _own_ ID; hence, the result of this > should be to load: > > a/d/e.js > > This means that a module must "know" its own ID, in some sense, and > hand it to its own loaders so that they can compute IDs relative to > that. > > The way we did that in Cajita, we just _gave_ the module access to > its own loader. But Mark Miller pointed out correctly that this was > a violation of the assumption that module functions are transitively > immutable -- i.e., powerless. If a module function is connected to > something that, at the mere utterance of "load()", goes out to the > internets and fetches guff, that is definitely an ambient authority. > So, what's to do? > > The simplest way to fix this is to allow a module to know its own ID > (i.e., the ID it was loaded by). Let's say each module function is > given a well-known constant in its lexical scope; for this > description, we will call it: > > _thisModuleId_ > > A module can then load something relative to its own ID by saying: > > load('foo', _thisModuleId_); > > and thus the module function does not have to close over its loader. > Capability security regained. The specific syntax of this sort of > thing remains to be hashed out. > > * * * * * > > Mark Miller made some concrete suggestions as well. He stipulated > two "load()" forms, which we name for the purposes of this > discussion only. "loadf" stands for "load function" and is the basic > "load()" we have now. To load a module function, do: > > moduleFunction = loadf('a/b/c'); > > which will load "a/b/c.js" as before. He also proposed "loadi", > which stands for "load instance" and actually instantiates the > module, in addition to loading its module function. To use it, do: > > moduleInstance = loadi('a/b/c', { x: 3, y: 4 }); > > The trick with "loadi" is that it has two conveniences: (a) it loads > a module function and instantiates it in one shot; and (b) it > desugars to: > > moduleInstance = loadf('a/b/c')({ loadf: loadf.for('a/b/c'), x: 3, > y: 4}); > > In other words, it automatically passes down to the module being > loaded a version of the current loader that is pre-configured to > search relative to the path "a/b/c". > > The reason why conveniences (a) and (b) are mixed together is that I > may call any given module function with two different loaders, so > providing a loader is an instantiation time, not a loading time, > thing. So say I load some module function: > > mf = loadf('a/b/c'); > > I can instantiate this with two different loaders: > > mi_1 = mf({ loadf: theFirstLoader, x: 3, y: 4 }); > mi_2 = mf({ loadf: theSecondLoader, x: 3, y: 4 }); > > and the object graphs created in mi_1 and mi_2, including the code > they are transitively connected to, may be wildly different because > -- well -- they were instantiated with different loaders. > > There is a final wrinkle in this. Note that we implement synchronous > "load()" on top of an async loader by stipulating that (i) the > topmost module loading is always async; and (ii) sync dependencies > are declared in the Caja module record, and are thus prefetched > prior to calling the module. Thus the sync dependencies are already > in the loader's cache when the code is running. Now, what if an > instantiating entity switches loaders along the way, and the loader > provided does _not_ have the requested module in the cache? The > answer is => this is a predictable failure mode. An exception is > thrown. This is, after all, a fairly uncommon case. > > Cheers, > > Ihab > > -- > Ihab A.B. Awad, Palo Alto, CA > _______________________________________________ > e-lang mailing list > [email protected] > http://www.eros-os.org/mailman/listinfo/e-lang _______________________________________________ e-lang mailing list [email protected] http://www.eros-os.org/mailman/listinfo/e-lang