proposal-compartments icon indicating copy to clipboard operation
proposal-compartments copied to clipboard

Virtual module cannot express "export function x"

Open Jack-Works opened this issue 3 years ago • 5 comments

Current format only allows export var x = function equivalent.

In order to support export function x, we need to add an extra stage on initialization.

initialize(env, context) {
    function x() {}
    env.x = x
    // this runs when VirtualModuleRecord.[[InitializeEnvironment]]
    return () => {
        // this runs when VirtualModuleRecord.[[ExecuteModule]]
    }
}

Jack-Works avatar Jul 13 '22 05:07 Jack-Works

Indeed. The initialization of modules has two steps: InitializeEnvironment and ExecuteModule. The InitializeEnvironment step can be skipped if the module body does not require it.

Both steps are especially meaningful with circular dependencies. Currently virtual modules only have one step, a function which is named initialize, which XS calls as its ExecuteModule step! Oops.

But I would prefer virtual modules to have two explicit hooks: initialize and execute. The initialize hook could be absent, but should be a synchronous function if present. The execute hook should be required but could be an asynchronous function.

patrick-soquet avatar Jul 13 '22 10:07 patrick-soquet

The problem with 2 separate hooks they're not in the same lexical context.

const a = module {
    export function a()
    a()
}

Two separate hooks are not friendly to down-level compiling.

const a = {
    initialize(env) {
        function a() {}
        env.a = a
    },
    execute(env) {
        a() // Oops!
    }
}

By this form, it can naturally inherit the lexical context.

initialize(env, context) {
    function a() {}
    env.a = a
    // this runs when VirtualModuleRecord.[[InitializeEnvironment]]
    return () => {
        // this runs when VirtualModuleRecord.[[ExecuteModule]]
        a() // Fine!
    }
}

Jack-Works avatar Jul 13 '22 10:07 Jack-Works

Would it make sense to have separate protocols for exec and init+exec?

I’m inclined to rename the existing initialize method (back) to execute given the distinctions revealed in this issue.

kriskowal avatar Jul 13 '22 17:07 kriskowal

can't a transpiler just introduce a new unique variable? babel does that all over the place.

devsnek avatar Jul 13 '22 17:07 devsnek

@devsnek To have separate initialize/execute methods? It doesn't work if they are called more than once, because they would use the same variable.

Babel compiles to SystemJS (the only module system that can emulate ESM) in a similar way to what's proposed in https://github.com/tc39/proposal-compartments/issues/70#issuecomment-1183039998:

System.register([], function (_export, _context) {
  "use strict";

  function a() {}

  _export("a", a);

  return {
    setters: [],
    execute: function () {
      a();
    }
  };
});

nicolo-ribaudo avatar Jul 13 '22 22:07 nicolo-ribaudo