2013-03-12 Meeting Notes

John Neumann, Norbert Lindenberg, Allen Wirfs-Brock, Rick Waldron, Waldemar Horwat, Eric Ferraiuolo, Erik Arvidsson, Luke Hoban, Matt Sweeney, Doug Crockford, Yehuda Katz, Brendan Eich, Sam Tobin-Hochstadt, Alex Russell, Dave Herman, Adam Klein, Edward Yang, Dan Stefan, Bernd Mathiske, John Pampuch, Avik Chaudhuri, Edward O'Connor, Rick Hudson, Andreas Rossberg, Rafeal Weinstein, Mark Miller

Opening

Introduction

Logistics

Adoption of Agenda

Mixed discussion regarding scheduling over the course of the 3 days.

Approved.

Approval of January 2013 Meeting Notes

Approved.

Adobe

John Pampuch: Here to help accelerate the ES6 spec, positive motivation. Excited about Modules, concurrency, debugging and profiling specifications.

Bernd Mathiske: Background as trained language designers and implementors and here to help.

John Pampuch: Also excited about asm.js

Bernd Mathiske: Not sure about the spec status/prospects of asm.js.

Edit (2013-03-22) blogs.adobe.com/standards/2013/03/21/adobes-ecma-tc-39-involvement

4.9 JSON, IETF changes

(Presented by Doug Crockford Crockford)

Currently, JSON is an RFC, informational, the IETF version will be an internet standard and there is a minor correction that affects ECMAScript.

The use of "should" in 15.12.2

Alex Russell: What is the motivation of the change?

Doug Crockford: The change involves the mistake of using "should" w/r to multiple same-named keys error. Multiple same-name keys are invalid and must throw an error (vs. "should" throw an error)

Luke Hoban: This is a breaking change

Dave Herman: The worst being the use case of multiple, same-named keys as comments

Doug Crockford: That's stupid

Yehuda Katz: That's based on on your recommendation to use a keyed entry as a comment, so people naturally used the same key, knowing they'd be ignored.

Doug Crockford: I would certainly never recommend that practice

Yehuda Katz: It was a side-effect

Alex Russell: Which key is used now?

Allen Wirfs-Brock: The last one wins.

Alex Russell: Is that the root of the security vector?

Doug Crockford: Not in ES, but in other encodings

Alex Russell: Order matters, unescaped content that follows...

Doug Crockford: The current spec says "[they should not]", but will say "[they must now]"

Yehuda Katz: Let's define an ordering and make it cryptographically secure.

Doug Crockford: (recapping to Mark Miller, who just arrived)

Mark Miller: You can't do that. (laughs)

Mark Miller: You can't change "should" to "must"

Yehuda Katz: Agreed, you cannot change JSON, there are too many JSON documents in existence.

Mark Miller: Agreed.

Alex Russell: It's possible to ignore this change?

Doug Crockford: Yes

Dave Herman: Then why are we creating a dead letter?

Mark Miller: ES has a grammatical specification for validating and parsing JSON. Anything that is not conformant JSON, would not parse. This change loses that property.

Doug Crockford: Or we don't change the spec

Mark Miller: The way that you properly reject our favorite fixes, I think you should apply to your favorite fixes

Doug Crockford: I'll consider that

Alex Russell: There is considerable opposition to this change

Doug Crockford: Two choices...

  1. Make it an error
  2. Continue to take the last one

Doug Crockford: Decoders have license to do what they want with non-conformant material. Encoders must be conferment to new changes.

Mark Miller: Our current encoder conforms...

Allen Wirfs-Brock: I don't think it does... reviver/replacer

Mark Miller: No, can only apply objects instead of the original objects.

Alex Russell: Did not realize the production/consumption distinction of this change.

Waldemar Horwat: Supports this change. ECMAScript is already conformant because it never generates duplicate keys.

Mark Miller: With this change ECMAScript would have two unappealing choices: A. No longer be a validating parser (i.e. a parser that doesn't allow any optional syntax or extensions, even though extensions are permitted by the JSON spec). B. Do a breaking change by throwing errors when seeing duplicates when parsing.

Conclusion/Resolution

  • Revisit this, after Doug Crockford has made a final decision. - FTR Majority opposition, no consensus.

4.12 StopIteration/Generator

(Presented by Dave Herman)

dherman/iteration-protocols

Dave Herman: ...Confirms that there is lack of understanding for Generator "instances"

Mark Miller: Clarify terminology

Dave Herman: Generator objects are instances of Iterators, in that they have a next method. The current design is based on a thrown StopIteration

C#, Java, Python apis for comparison.

My opinion, a single method is win.

Concrete proposal

  • The benefit of a single method
  • Not based on exceptions
  • Compatible with Generator semantics

Iterator API object has a single method:

{
  next() -> { done: false , value: any }
          | { done: true[, value: any] }
}

b/c generators can return an argument, if you're using a return value

function* f() {
  yield 1;
  return 2;
}

for for-of this doesn't matter, but for libs like q, task.js this is useful for pause and resume with value

If we didn't care, the result value can be omitted

This API was pleasant to write and works nicely with existing idioms

Mark Miller: Requires allocation for every iteration?

Dave Herman: Yes, will still need the object allocation, but

Waldemar Horwat: Does next return a fresh object? or can reuse the same?

Dave Herman: Can reuse

Allen Wirfs-Brock: For every iterator in the spec, we need to specify a fresh or reused object?

Dave Herman: Yes.

Yehuda Katz: The current API, able to do yield ...returns a promise...

Dave Herman: Can still do that, this change is internal and w/r to performance, this should be highly optimizable.

Allen Wirfs-Brock: Anything that uses a method based implementation, will be more optimizable through calls vs exception.

Dave Herman: I've never seen an iterator API that didn't have some performance issues

Allen Wirfs-Brock: (refutes) Any method based approach can be better optimized over exception based approaches.

Dave Herman: I don't have a solid performance story, but the feedback I'm getting is that there is negative concern about the StopIteration approach, whereas this approach mitigates these concerns. Issues arise when dealing with multiple iterators

Waldemar Horwat: If you try throwing StopIteration across iterators, it will be caught

Allen Wirfs-Brock: Or it won't

Erik Arvidsson: Surprising: If any function throws a StopIteration, it will jump out of the for-of.

Allen Wirfs-Brock: I noticed this in the examples shown in the github repo

Waldemar Horwat: Why I'm in favor... Throwing StopIteration across places where no iterators exist and if code is refactored so that an iterator is present, you'll experience unexpected behavior. (This suffers from the same capture flaws as Lisp's old dynamic scoping.)

Luke Hoban: When we last talked about this, we whiteboarded the priority order. for-of is the primary case, generator authoring is the secondary case. Cases affected by this: direct API consumption as third and direct API authoring is fourth

If we're really sure the engines will do the work to optimize these things?

A. will this slow down implementation? B. won't be willing to implement due to poor performance?

Alex Russell: No implementation wants to ship something that will potentially be slow

Luke Hoban: Of course, but StopIteration has to go.

Mark Miller: One allocation per loop

Waldemar Horwat: So is this

Mark Miller: Only if you reuse the record

Luke Hoban/Waldemar Horwat: Of course and that's what you want

Mark Miller: Then, as Allen said we need to specify this

Dave Herman: My inclination would be to use a fresh object each time

Allen Wirfs-Brock: ...you know the first time, because it's the first time that next is called,

Mark Miller: My proposal is that you provide stop token as a parameter of next(stop), every time. next(stop) would return either the next value or the stop token.

Dave Herman: (clarifying) "iteration" is one time around the loop. "loop" is the entire the operation.

Waldemar Horwat: It's possible for next(stop) to cause havoc from one iteration to another by caching one next call's stop parameter and returning it from a different next call.

[Someone had also presented a variant of the proposal where <stop> was a field on the iterator instance instead of an argument to next.] Waldemar Horwat: This would create funky failures if, for example, you had an iterator that did a deep traversal of an object tree and said tree happened to include the iterator instance.

Mark Miller: In order to not allocate on every iteration, you have specify (???)

Mark Miller: A new stop token would be generated per loop.

Waldemar Horwat: What's a loop? This gets confusing when you have iteration adaptors.

Allen Wirfs-Brock: If the client passes in the token on next(), then it's the client's burden

Mark Miller: Anything that's unforgable, unique, or itself side affectable.

Dave Herman: Is there support for Mark's API?

Rick Hudson: If you use Mark's API, overtime...

Mark Miller: My API reuses the object for the iterations of the loop, by passing it back in as an argument to next()

Rick Hudson: To avoid the cost of allocation?

Mark Miller: Yes, but only as a token

Erik Arvidsson: You can have a return value in a generator so the object passed in needs to be mutated to include the return value in case of end of iteration.

Mark Miller: That is a downside of this proposal, where StopIteration would carry the value.

Dave Herman: (examples of the two proposals)

Dave's

{
  next() -> { done: false , value: any }
          | { done: true[, value: any] }
}

Marks's

{
  next(X) -> any | X
}

Allen Wirfs-Brock: (suggests an alternative: pass an object to next, on which next sets the result)

Sam Tobin-Hochstadt: ...is hostile to implementors and user code.

Andreas Rossberg: That's the C-style of doing it.

Waldemar Horwat: Suppose the iterator takes an object and returns all the properties, but calls on itself?

Dave Herman: Mark's proposal is broken, because it doesn't work with return values of generators.

Mark Miller: Agreed.

Dave Herman: Don't think that we're approaching consensus, but don't let your idea of perfect cloud judgement. I'm asking engine implementors if this is appealing. The concern over StopIteration is real.

Allen Wirfs-Brock: This is certainly better then the current plan of record

Alex Russell: Agree.

Bernd Mathiske/John Pampuch/Avik Chaudhuri: Agree

Bernd Mathiske: This is also future proof and works well with concurrency and the semantics are sound. It's also easy to implement and optimize.

Allen Wirfs-Brock: All spec iterators/generators must specify a reused iterator or fresh

Mark Miller: (further support for Allen Wirfs-Brock's claim)

Dave Herman: Not sure if we're trading short term wins for long term losses. Are there long terms

Andreas Rossberg: There is another secondary effect that it encourages better GC

Allen Wirfs-Brock: This shouldn't be a problem for a good GC

Mark Miller: I'm really only concerned about the loop aspect

Alex Russell: We have the tools to work with hot loops

Waldemar Horwat: Alex's point about the escape valve is key

Dave Herman: Not discounting the needs of the developers/user code. The method API is appealing, vs. StopIteration

Rick Waldron: Agree.

Dave Herman: (Shows example of C#)

Allen Wirfs-Brock: The third use case that Luke gave, using an iterator and the fourth use case, creating an iterator. ...This API is more complex for user code ...More ways for client code to go wrong

Bernd Mathiske: Disagree, this is a safer.

Dave Herman: Don't get out of sync. Argue that the Java and C# API are too error prone.

Bernd Mathiske: Agree, this is actually superior to the Java and C# APIs

Andreas Rossberg: This is actually the path you'd want in typed languages, minimizes state space

Dave Herman: I want to see a better overall interface for iterators and generators, without jeopardizing the acceptance.

Mark Miller: In favor of this API, if the implementors are not objecting. Although I don't like the API itself.

Dave Herman: Agree, I prefer the pure, stateless proposal

Allen Wirfs-Brock: If an object is passed an argument, the object is used as the value bucket.

Dave Herman: Still mutates the object

Allen Wirfs-Brock: But it mutates an object that you've explicitly provided

Bernd Mathiske: The issue is not the allocation, but that you have to go to heap at all.

Andreas Rossberg: If you do this pre-allocation thing, it might be observable

Bernd Mathiske: But that's the case either way

Dave Herman: Is the mutable version going to harm optimization?

Andreas Rossberg: Yes: the object may be shared, in which case mutation may become observable from the distance, and cannot be optimized away

Rick Hudson: If the object being mutated escapes to an old mutation, this kills potential optimizations.

Dave Herman: Seems like consensus on the pure, stateless version of this:

{
  next() -> { done: false , value: any }
          | { done: true[, value: any] }
}

John Pampuch: "more" vs. "done"?

(can discuss further)

Conclusion/Resolution

  • Rough agreement (between those present) on pure, stateless version of:
{
  next() -> { done: false , value: any }
          | { done: true[, value: any] }
}

...To replace StopIteration

  • Always has an own property called "value":
var i1 = (function *f() {
  return;
})();

"value" in i1.next();

var i2 = (function *g() {
})();

"value" in i2.next();

var i3 = (function* h() {
  return (void 0);
})();

"value" in i3.next();
  • Built-in iterators should be specified as returning a fresh value. - See gist.github.com/dherman/5145925
  • Without Brendan, a champion of iterators and generators, don't have full consensus

4.2 Modules

(Presented by Dave Herman, Sam Tobin-Hochstadt, Yehuda Katz)

See: gist.github.com/wycats/51c96e3adcdb3a68cbc3

Slides (PDF, will prompt download): meetings:modules-march-2013.pdf

Dave Herman: We're committed to making this happen for ES6, it's too important to miss and I'm going to do whatever it takes. Please remember that you can always bring specific issues directly to us (Dave Herman, Sam Tobin-Hochstadt, Yehuda Katz).

...Not going to spend time on syntax. Focus on Module loading semantics to address any outstanding issues, spent last two months working with Sam and Yehuda and polling community leaders to get use cases to work with.

Recognize that some use cases may not be covered, but that's ok.

Module Loading Semantics

...Currently a notion of having a string-name registry

...Move towards having a separate space for module registration

Minimalism - IN Nested Modules - OUT

module "libs/string" {
  export function capitalize(str) {
    return (make the string capitalized)
  };
}

module "app" {
  import { capitalize } from "libs/string";
}

The registry corresponds to a Loader which creates a Realm

Mark Miller: But you can have more then one Realm

Dave Herman: Think of Loader as a virtual "iframe", as a concrete way of describing it. When you create an "iframe", you get a whole new global object with it's own DOM. A Loader creates a "sandbox" global that can share system intrinsics.

The System loader.

var capitalize = System.get('libs/string').capitalize;
var app = System.get('app').app;

Custom loader:

var sandbox = new Loader({ intrinsics: System });

sandbox.set('app', System.get('app'));
sandbox.get('app') === System.get('app'); // true

sandbox.eval("import { capitalize } from 'app'; capitalize('hi')"); // "Hi"

Acts like a map, .get() will get the module

[Module pipeline diagram]

             module name
                  |
                  V
              normalize
                  |
                  V
               resolve
                  |
                  V
               fetch
                  .
                  .
                  V
              translate
                 |
                V
                link

Produces one of three values:

  • undefined: default linking behavior
  • Module: registers module instance object directly
  • {imports : [ModuleName], execute : (Module ...) -> Module, exports : [String]} : invokes execute to produce module, exports optional

...

Use Case: Module Paths

System.ondemand({
  "http://code.jquery.com/jquery-2.4.js": "jquery",
  "backbone.js": [ "backbone/events", "backbone/model" ]
});

...is sugar for...

System.resolve = function(path) {
  switch (path) {
    case "jquery":
      return "http://code.jquery.com/jquery-2.4.js";
    case "backbone/events":
    case "backbone/model":
      return {
        name: "backbone.js",
        type: "script"
      };
  }
};

Mark Miller: This is changing the behavior only at the system Loader?

Dave Herman: Yes.

Sam Tobin-Hochstadt: This is the API that several people indicated was important during the last meeting.

Use Case: ...?

Use Case: Compile To Jaswanth Sreeram

 System.translate = function(src, options) {
  if (!options.path.match(/\.coffee$/)) {
    return;
  }
  return CoffeeScript.translate(source);
}

Luke Hoban: Is this updated on the Wiki?

Dave Herman: Will update. Much of the changes are about refining API and making common things easy and most things possible

Use Case: Custom AMD

Creating custom translations for extensions...

import { data: foo } from "text!foo";

```js
System.normalize = function(path) {
  if (/^text!/.test(mod)) {
    return {
      normalized: mod.substring(5) + ".txt",
      metadata: { type: "text" }
    };
  }
  // fall-through for default behavior
}

System.translate = function(src, { metadata }) {
  if (metadata.type === "text") {
    let escaped = escapeText(src);
    return `export let data = "${escaped}"`;
  }
  // fall-through for default behavior
}

Waldemar Horwat: Why would you want to do it this strange way (escape text only to then eval it) instead of just letting the text be? [It feels kind of like the folks doing eval("p." + field) instead of p[field]].

Dave Herman: (explains James Burke's summary of static asset loading)

Use Case: Importing Legacy Libraries

(Specifically, not libraries that use CommonJS or AMD, but libraries that mutate the global object)

var legacy = [ "jquery", "backbone", "underscore" ];

System.resolve = function(path, options) {
  if (legacy.indexOf(path) >= -1) {
    return {
      name: path, metadata: { type: "legacy" }
    };
  } else {
    return {
      name: path, metadata: { type: "es6" }
    };
  }
};
function extractExports(loader, original) {
  var original =
    `var exports = {};
    (function(window) { ${original}; })(exports);
    exports;`

  return loader.eval(original);
}

System.link = function(source, options) {
  if (options.metadata.type === 'legacy') {
    return new Module(extractExports(this, source));
  }

  // fall-through for default
}

Luke Hoban: Once we ship this, we want people to start using modules as soon as possible. How?

Yehuda Katz: Realistically, a "plugin" for something like require.js will have to provide an ES6 "shimming" mechanism.

Luke Hoban: To paraphrase, we're providing the primitives that make the common cases easy to overcome. What about the legacy libraries that won't be brought up to date? Can we provide a simple mechanism?

Dave Herman: No, legacy libs that just expose themselves to the global object, without any sort of shimming mechanism are out of reach

Luke Hoban: Thank you, that's a sufficient answer

Use Case:

Import AMD style modules and Node style modules. Effectively, ES6 module importing from non-ES6 module.

There is no way to tell

System.link = function(source, options) {
  if (options.metadata.type !== "amd") { return; }

  let loader = new Loader();
  let [ imports, factory ] = loader.eval(`
    let dependencies, factory;
    function define(dependencies, factory) {
      imports = dependencies;
      factory = factory;
    }
    ${source};
    [ imports, factory ];
  `);

  var exportsPosition = imports.indexOf("exports");
  imports.splice(exportsPosition, 1);

  function execute(...args) {
    let exports = {};
    args.splice(exportsPosition, 0, [exports]);
    factory(...args);
    return new Module(exports);
  }

  return { imports: imports, execute: execute };
};

Bernd Mathiske: Could you postulate that exports and

Dave Herman: You could but, unrealistic

Bernd Mathiske: Could be optimizing for module provider, but not consumer... ...

Mark Miller: What does the Module constructor do? Dave Herman: Copies the own properties of the given object.

Mark Miller: What is the job of the System.link hook?

Sam Tobin-Hochstadt: To go from a piece of JavaScript source code to module instance object, translate is string->string.

Waldemar Horwat: Is it a module or Module instance?

Dave Herman: Module instance object

Take the source code, all the deps, finds all the exports, links them together.

The link hook can return

  1. undefined for the default behavior
  2. A Module instance, where everything is done and complete
  3. An object, with list of deps and factory function to execute at some later time (eg. when all deps are downloaded and ready)

Yehuda Katz: Explains that a two phase system is required whether you're using node, AMD or anything. Now you can use ES6 provided hook.

Bernd Mathiske: Optionally specify the list of exports?

Dave Herman: Yes.

Conversation about specific example.

Mark Miller: Clarify... noting that the positional args is similar to AMD positional args

Dave Herman: Yes.

Andreas Rossberg: No static checking for non-ES6 modules?

Dave Herman: Yes, it's a hole that can't be filled if we want interop from AMD->ES6 and ES6->AMD (or node)

Andreas Rossberg: Concern about having two imports, checked and unchecked. (implementation complexity concern)

Bernd Mathiske: The alternative is to not support AMD and provide only one imports

Sam Tobin-Hochstadt/Rick Waldron: This is an option, but a worse option.

...Discussion re: static checking for non-ES6 modules

Andreas Rossberg: Every single construct, import, loading etc now has two different semantics to support.

Bernd Mathiske: Forces users into thinking about which they need... optimizing for module authors, not module users. The wrong case... otherwise enforce static checking for all module code

Alex Russell/Sam Tobin-Hochstadt: Not possible for all existing code

Sam Tobin-Hochstadt: (whiteboard) Indirection via dynamic object makes static checking impossible.

For example, if you write the code:

import { a } from "some.js"
... a ...

where "some.js" is an AMD library, then there's no static checking, but if you refactor "some.js" to be an ES6 module, you automatically get static checking. But if you don't support this use case, then there's indirection:

import { exports } from "some.js"
... exports.a ...

And changing "some.js" to use ES6 never results in new static semantics.

...Mixed discussion re: dynamic checks vs static checks.

Bernd Mathiske: Was under the impression that the dynamic checks might be too late, but it has now become clear that they happen early enough

Sam Tobin-Hochstadt: Cannot create references across Module instances to dynamic module code.

Mark Miller: the world of Jaswanth Sreeram uses feature detection, on the AMD side... can AMD code feature test?

Sam Tobin-Hochstadt: (refers to an early slide, which shows example of importing module as single object, properties can then be tested for)

Mark Miller: (confirms that Sam Tobin-Hochstadt answers Q)

Dave Herman: Pause on the Question of dynamic import/export (Returns to the pipeline diagram) ...The "fetch" hook is the part where you go get the bits

Dave Herman: (Slide: 1. Load and Process Dependencies Diagram) (Slide: 2. Link)

Alex Russell/Dave Herman: Note that browsers can provide their own plugin points for the Fetch step

Mark Miller: All of the hooks have been executed and there is no user code? If this fails, there are no side effects?

Dave Herman: Correct

Andreas Rossberg/Sam Tobin-Hochstadt: During

Dave Herman: Modified the registry, but there is an inflight loading happening, when the inflight is finished, it will pave the changes to registry. (last op wins)

Andreas Rossberg: When you evaluate a script that imports module Foo, which runs hooks that in turn import Foo into the module registry, what happens?

Allen Wirfs-Brock: Why are they operating in the same Realm?

Dave Herman: It sounds like an objection to modifying the list of modules in the registry by downloading code that modifies the list of modules in the registry...

Sam Tobin-Hochstadt: Imagine we didn't have loader hooks, all you could do was eval and had two XHRs that fetched and eval'ed. We'd still have the same issues that we'd have with loader hooks, it's a problem with mutation and concurrency.

Andreas Rossberg: Agree that the fundamental problem will always be there, but have a problem with shared global object for all modules.

Dave Herman: If the same module is attempted to be defined in two places, that's an error and is a bug.

Andreas Rossberg: Only when within the same compilation stage, silent overwriting otherwise.

Waldemar Horwat: What if module A depends on both B and C and the initialization of B fails?

Dave Herman: C remains uninitialized but present in the registry

Waldemar Horwat: This breaks the model. It's not C's fault that its initializer didn't run.

Allen Wirfs-Brock: Mark C as never having its initializer attempt to run and run it the next time it's imported.

Dave Herman: Moving to next slide

(Slide: 3. Execute)

Produces "Result"

Note that each step in the 3 parts has an Error path:

  1. load/syntax error
  2. link error
  3. runtime exception

...Mixed discussion re: execution despite exceptions

...Mixed discussion clarifying fetch semantics (1. Load and Process) re: dynamically building URLs to batch load? re: browser knowledge of sources?

Luke Hoban: What does the synchronous timeline of Slide 1 look like?

Dave Herman: All normalize hooks first (need names and locations), then all resolve hooks

Use Case: Importing into Node

System.resolve = function(path, options) {
  if (node.indexOf(path) > -1) {
    return { name: path, metadata: { type: 'node' } };
  } else {
    return { name: path, metadata: { type: 'es6' } };
  }
};

function extractNodeExports(loader, source) {
  var loader = new Loader();
  return loader.eval(`
    var exports = {};
    ${source};
    exports;
  `);
}

System.link = function(source, options) {
  if (options.metadata.type === 'node') {
    return new Module(extractNodeExports(this, source));
  }
}

Use Case: Single Export Modules

Dave Herman: Brought this up 2 meetings ago, had a proposal that wasn't ready, it was shot down. This is something that I'm being told is very important and I agree with them. We can accommodate single exports via design protocols, but the developer community may not like it.

Dave Herman/Yehuda Katz: (walk through the System.link implementation)

Dave Herman: Can, should do better. Goal: Simple syntactic sugar. It's important, we will address it and we will do so with syntactic sugar. We will create a means by providing an "anonymous export". We will review the "sugar" at the next face-to-face meeting.

...Recognizes the community frustration regarding lack single/anonymous exports.

...No dissent.

Luke Hoban: (Questions about how this works with the previously shown use cases)

...

Yehuda Katz: (Shares anecdotal experience from developing the ES6 transpiler that was adopted by Square. Positive experience.)

Sam Tobin-Hochstadt: Updated/removed junk from wiki

Luke Hoban: Can imports be in scripts?

Sam Tobin-Hochstadt: Yes

Dave Herman: There was originally a use case that involved jQuery, we can't satisfy this without breaking everything (there is no way to be ES 3, 5, 6 at the same time)

But...

if (...some detection...) {
  System.set("jquery", ...);
}
<!--
once this is loaded, the jQuery module is
registered and available for all scripts
-->
<script src="jquery.js"></script>
<!--
which means all future scripts may have this:
-->
<script>
import { $ } from "jquery";
</script>

Luke Hoban: What about concatenation cases?

Dave Herman: (whiteboards example of System.ondemand)

System.ondemand({
  "all.js": [ "a", "b", "c" ]
});

Allen Wirfs-Brock/Sam Tobin-Hochstadt: (whiteboard)

m.js:

module "m" {
  export let a = 1;
}

n.js:

module "n" {
  export let b = 2;
}

Needs:

System.ondemand({
  "m.js": "m",
  "n.js": "n"
});

If you concatenate?

m.js + n.js = concat.js...

Needs:

System.ondemand({
  "concat.js": [ "m", "n" ]
});

Arrays for files that contain multiple things

...

Andreas Rossberg: We're over-prioritizing for concatenation. The language shouldn't be hostile, but should stop at good enough. We shouldn't optimize the design of the language around a secondary concept

Allen Wirfs-Brock: modules are a concrete concept in the language, we need to focus on these as a building block

Luke Hoban:

Sam Tobin-Hochstadt: The claim that concatenation is going to become a not-important part of the web is ludicrous

Andreas Rossberg: I think that mid-term concatenation will harm performance

Yehuda Katz: Do you think that concatenation will go away?

Andreas Rossberg: In the long term, it might

Yehuda Katz/Sam Tobin-Hochstadt: This is what is ludicrous

...Mixed discussion re: library vs. language

Allen Wirfs-Brock: There is a standard loader, defined by the language

...From Arv: Alex Russell: Joining files to optimize download and compilation

Sam Tobin-Hochstadt: YUI optimized for reality and found that concatting is important

Yehuda Katz: Should Ember ship 100 files?

Alex Russell: Any modern library has a lot of files. Apps/libraries are making trade-offs to get good performance.

Doug Crockford: Caching is not working. Browser will get better.

Alex Russell: SPDY will make things better

Yehuda Katz: Even with SPDY, there is a lot of IO

Andreas Rossberg: It is perfectly fine to depend on a tool for concat

Erik Arvidsson: We are designing based on concatenation. We should take that out of the picture. We can always write compilers that does the linking.

Andreas Rossberg/Luke Hoban: With a compiler you can do linking/bundling and existing and future tools can do this.

Sam Tobin-Hochstadt/Dave Herman: There will be holes in these.

Luke Hoban: module "a" { ... } is leading developers down the wrong path

Sam Tobin-Hochstadt: Recommmend doing modules the node style, where each file is a module

Yehuda Katz: AMD developers use a build system that adds the name to the define(). They don't name the modules in their source. The build system names the modules.

Mark Miller: AMD experience speaks in favor of a concatenator.

Sam Tobin-Hochstadt: You will get a compile time error if you import a file that contains a module. ...

Andreas Rossberg: How about adding a way to just register a module as a string containing the source of its body as if it was a file.

Alex Russell: Then you have to allocate the string ...

Allen Wirfs-Brock: Wants to use module "abc" { ... }. It is a good way to structure code. And you don't want to tie this to your configuration management ...

Sam Tobin-Hochstadt: The strength of the system is that it supports both

Andreas Rossberg: The approach Allen wants is not well supported because it lacks lexical scoping

Alex Russell: If we use a string literal we cannot check the code to do prefetching etc

Andreas Rossberg: It is a string so the string only needs to be lexed, then the parsing etc can be paralellized, not so with embedded module declaration ...

Andreas Rossberg: There is no way to not modify the global registry when defining a module.

Dave Herman: The file system (in SML) is also a shared registry. The module registry is no different

Andreas Rossberg: Disagree. There is no way to create a local module here

Sam Tobin-Hochstadt: Jaswanth Sreeram has a lot of ways to struccture code: functions, classes etc and modules do not need to fill this role

Andreas Rossberg: More interested in preventing accidents due to name clashes.

...Mixed discussion of module syntax related concerns

Dave Herman: Ability to prevent people from using module syntax?

Mark Miller: Yes

Sam Tobin-Hochstadt: For Andreas' concern, look for the names of module declaration strings, check the registry and if any already exist, error.

...Defining a loader with right hook, prevent the mutation of the registry by anyone that does not have access to the loader

Mark Miller: Satisfied from a security perspective.

Andreas Rossberg: Would prefer for the default behavior to error, need to be explicit if you want module to override in an imperative manner.

Dave Herman: Not opposed to moving towards scoped modules in the future. Just worried about complexities.

Andreas Rossberg: Only concerned about import scope semantics

Sam Tobin-Hochstadt: concern is that polyfills have to use eval and then System.set

Andreas Rossberg: good to make it clear that polyfills are doing some special

Dave Herman: agree with Andreas Rossberg about polyfills

Sam Tobin-Hochstadt: This is something to be deferred without blocking progress, but ok with changing to error to achieve consensus.

Yehuda Katz: agree with Sam Tobin-Hochstadt about consensus, but potentially concerned.

Conclusion/Resolution

- Default declarative form of a module is an error if a module of the same name already exists in the module registry.

  • Using System.set to overwrite an existing module is not an error.
  • Behavior of errors during module initialization (when some module initializers don't even get started) is still unresolved.