Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Status Report: ES6 Modules

dherman
November 21, 2013

Status Report: ES6 Modules

My status report (draft complete!) of ES6 modules at the November 2013 TC39 meeting.

dherman

November 21, 2013
Tweet

More Decks by dherman

Other Decks in Programming

Transcript

  1. END-TO-END DRAFT DONE • Linking semantics • Loading semantics •

    Execution semantics • Loader API • Dynamic (CommonJS/AMD/Node) compat layer • Bonus: literate implementation starting to pass simple tests
  2. ES6 DRAFT • Updated syntax for new parameterized grammar •

    Static semantics done and edited by Allen
  3. NEXT STEPS • Improve the formatting • Improve spec text

    (with Allen's help) • Integrate into Allen's draft
  4. 2 > 3 • Three goal non-terminals (Module, Script, ScriptAsync)

    is one too many • Eliminating import from scripts simplifies the loader API — loading is purely about modules • <script async> was a non-starter anyway!
  5. <MODULE> • (Not part of ECMAScript proper, of course) •

    As concise as <script> • More concise than <script async> • Allows inline source • Implicitly strict (as all modules are) • Named <module>: provide source up front • Anonymous <module>: async but force execution
  6. <MODULE> IS A BETTER 1JS • Better global scoping: starts

    in a nested scope • To create persistent globals, must opt in by mutating window/this • Conservation of concepts: no special semantics required for reforming global scope; just a module • A carrot to lead away from blocking scripts • Still accessible to scripts via System.import
  7. CONSTRUCTOR new Loader({ normalize: n, // -> Prom<stringable> locate: l,

    // -> Prom<address> fetch: f, // -> Prom<source> translate: t, // -> Prom<source> instantiate: i // -> Prom<factory?> })
  8. REGISTRY API l.get(name) // Module? l.set(name, m) // void l.has(name)

    // boolean l.keys() // Iter<string> l.values() // Iter<Module> l.entries() // Iter<[string,Module]>
  9. SMELLS • Loaders are really about modules, but eval/ evalAsync

    represent scripts • Mixing concerns: scripts vs modules • Mixing concerns: module loading vs sandboxing • Capability hazard:
 new Loader({ intrinsics: otherLoader })
  10. REALMS : GLOBALS : INTRINSICS : EVAL HOOKS • Global

    object & Function/eval are intertwingled • Intrinsics and standard constructors, prototypes are intertwingled • Realm and intrinsics are intertwingled • Everything is deeply intertwingled ;-P
  11. REALM API let r = new Realm({ ... }); r.global.myGlobal

    = 17; r.eval(...) ! https://gist.github.com/dherman/7568885
  12. SEPARABLE FROM LOADER API • Important, but it's a separate

    concern • Loader defaults to its own realm • Realms: sandboxing, sync script execution • Loaders: async module execution
  13. REALM API let realm = new Realm({ eval: ..., Function:

    ... }, function(builtins) { // global object starts empty // populate with standard builtins mixin(this.global, builtins); });
  14. INDIRECT EVAL let caja = new Realm({ eval: ... });

    ! ! ! caja.eval(` (0,eval)("1 + 2") `);
  15. INDIRECT EVAL let caja = new Realm({ eval: { indirect:

    (s) => { ... } } }); ! caja.eval(` (0,eval)("1 + 2") `);
  16. DIRECT EVAL let caja = new Realm({ eval: ... });

    ! ! ! ! caja.eval(`{ let tmp = f(); eval("tmp") }`);
  17. DIRECT EVAL let caja = new Realm({ eval: { direct:

    { translate: (s) => { ... } } } }); caja.eval(`{ let tmp = f(); eval("tmp") }`);
  18. DIRECT EVAL let caja = new Realm({ eval: ... });

    ! ! ! ! caja.eval(`{ let eval = console.log; eval("hello!") }`);
  19. DIRECT EVAL let caja = new Realm({ eval: { direct:

    { fallback: (f, ...rest) => { ... } } } }); caja.eval(`{ let tmp = f(); eval("tmp") }`);
  20. FUNCTION let caja = new Realm({ Function: ... }); !

    ! ! ! caja.eval(` Function("x", "return x + 1") `);
  21. FUNCTION let caja = new Realm({ Function: (args, body) =>

    { ... } }); ! ! ! ! caja.eval(` Function("x", "return x + 1") `);
  22. FUNCTION* let caja = new Realm({ Function: ... }); !

    ! ! ! caja.eval(` (function*(){}).constructor("x", "return x + 1") `);
  23. FUNCTION* let caja = new Realm({ Function: (args, body, prefix)

    => { ... } }); ! ! ! ! caja.eval(` (function*(){}).constructor("x", "return x + 1") `);
  24. REALM API let r = new Realm({ eval: { indirect,

    direct: { translate, fallback } }, Function });
  25. CROSS-DOMAIN MODULES • Browser loader should allow cross-domain loads •

    ServiceWorker requires cross-domain sources (XHR) and sinks (<img>, <script>, etc.) • Browser's System.define should be a sink • No problem: type of src parameter unconstrained in ES semantics — polymorphism to the rescue • IOW, each loader determines for itself what types are allowed for source
  26. STREAMING MODULES • Might want to support streaming I/O in

    future • Polymorphism allows admitting stream objects for .define and .module in future
  27. 21 NOV 13 RESOLUTIONS • \o/ • Add l.delete(name) •

    Review race conditions and error checking around pending loads • Eliminate Function realm hook (can implement by mutating global.Function and global.Function.prototype.constructor) • {indirect,direct}Eval instead of eval.{indirect,direct} • indirectEval translates source just like directEval.translate • Move Realm callback to named init option • If init option omitted, default to normal global object (all standard builtins, inherit from Object.prototype) • If init option supplied, empty global object with null [[Prototype]]