[e-lang] Module loading discussion

Jonathan Rees jar at mumble.net
Thu Dec 3 05:50:30 PST 2009


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, ihab.awad at gmail.com 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
> e-lang at mail.eros-os.org
> http://www.eros-os.org/mailman/listinfo/e-lang

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.eros-os.org/pipermail/e-lang/attachments/20091203/52472a0e/attachment.html 


More information about the e-lang mailing list