Hi Ihab

Would there be a way to determine id's of module instances beyond the
module being loaded.
EG something like moduleBNamespace = resolve(moduleBInstance)? Also
would there be a benefit
for a module to be able to query the loader for the set of namespaces
within its context?
Both approach introducing reflection capabilities to modules via their
loader, I'm wondering
it this is within the scope of modules and module loaders. I can think
of various use cases
where a module would want to resolve a namespace given an instance or
know what namespaces
are available.

Assuming _thisModuleId_ is exposed to every module would its object
properties be
_thisModuleId_ = {
  value: "a/b/c",
  writable: false,
  enumerable: false,
  configurable: false
}
Would the property be exposed outside of the module or be considered
private?

In terms of switching loaders (the last paragraph), would there be an
advantage to building a loader hierarchy similar to
java's where a loader may request a parent loader to find the module
reference if child and parent loaders
are mutually accessible within a sandbox?


Thanks
Kam



On Nov 18, 9:27 pm, [email protected] wrote:
> 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

Reply via email to