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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.