January 19 meeting notes
On Jan 19, 2012, at 19:40, Waldemar Horwat wrote:
Waldemar: What about read-eval-print loops? MarkM: Each eval inserts one more nested scope. Waldemar: What if someone does this:
let x = 3; function foo() {return x;} let x = 7; This would leave foo returning 3. MarkM: That's the proper behavior. Anything else has problems. Waldemar: [incredulous] Allen: We shouldn't spec read-eval-print loops.
In case it is relevant to the ‘problems’, I would like to remind MarkM that E used to behave in the return-7 way at REPL, and we abandoned it not because it wasn't nice REPL behavior but only because it meant that anything defined at top-level was forced to not be deep-frozen due to it closing over those slightly magic variables, but that is not an issue here since JavaScript doesn't have deep-frozen-in-that-sense functions.
(I'm not advocating returning 7; I’m just checking that 3 is returned for valid reasons.)
Waldemar Horwat <mailto:waldemar at google.com> January 19, 2012 4:40 PM
Discussion about scope of for-bindings. for (var x = ...;;) {...} will, of course, retain ES1 semantics. for (let x = ...;;) {...} Allen: This will behave as in C++: x is bound once in a new scope immediately surrounding just the for statement. DaveH: Strangely enough, this creates a new x binding in Dart at each iteration. There's an alternative semantics that creates an iteration-local second x inside the loop and copies it back and forth. Debate about whether to go to such complexity. Many of us are on the fence. Waldemar: What happens in the forwarding semantics if you capture the x inside a lambda in any of the three expressions in the head? If this happens in the initializer: DaveH's option: The lambda would capture an outer x. Alternative: The lambda captures a hidden second x. Waldemar's option: The lambda would capture the x from the first iteration. The let variable x is bound once through each iteration, just before the test, if for (let x = expr1; expr2;) {...} were: while (true) { let x = first_iteration ? expr1 : value_of_x_from_previous_iteration; if (!expr2) break; ... } MarkM: Just discovered that his desugaring has the same semantics as Waldemar's option.
for (const x = ...;;) {...} behaves analogously to let, whatever we decide let will do.
Those opposed earlier to new-binding-per-iteration hop back onto the fence. Waldemar, Brendan, and DaveH hop off the fence to now support it, as it will cure an annoying gotcha in practice. Looks like we have support for it now.
Yes kids, this means we are going with MarkM's lambda desugaring from:
So any closures formed in the body of such a for(let...;...;...) loop will capture the binding created afresh for that iteration. This avoids the nasty need for CoffeeScript "do" or the expanded JS equivalent of an IIFE surrounding the closure to create per-iteration storage for a copy of the loop control variable.
Contrary to Jon Zeppieri's good argument at
that
{ let x = 0; for (; x< n; x++) ... }
should have different behavior than
for (let x = 0; x< n; x++) ...
those of us left from the TC39 meeting (missing a few reps, short of quorum) favored the greater-good argument ofprogrammer who follow'let is the new var' and who form closures in loops benefiting from the fresh let binding being captured, instead of one binding per loop where the likely value of the binding is the terminating loop control.
Yay (I'm pretty sure).
Given that this desugaring will only kick in if a closure leaves the loop (right?), this is a case of automatically doing the right thing (and only if it’s warranted).
2012/1/19 Kevin Reid <kpreid at switchb.org>
On Jan 19, 2012, at 19:40, Waldemar Horwat wrote:
Waldemar: What about read-eval-print loops? MarkM: Each eval inserts one more nested scope.
This is not what users of REPL want or expect.
Waldemar: What if someone does this:
let x = 3; function foo() {return x;} let x = 7; This would leave foo returning 3. MarkM: That's the proper behavior. Anything else has problems.
Developers expect these lines to be part of a program they happened to type in, in the same scope.
Waldemar: [incredulous] Allen: We shouldn't spec read-eval-print loops.
The scope issues above are complicated by the need to augment the scope with REPL-specific values, aids to using the environment interactively. The simple way to implement REPL is eval, the simple augmentation is "with(REPL-stuff){ ...}"
So we have a feature highly prized by JS developers based on two languages features unloved on es-discuss: maybe Allen is on to something ;-).
jjb
Axel Rauschmayer <mailto:axel at rauschma.de> January 19, 2012 8:20 PM Given that this desugaring will only kick in if a closure leaves the loop (right?), this is a case of automatically doing the right thing (and only if it’s warranted).
Right, it's not observable without a closure.
The downside, if it is a downside, is that if you take a literal C/C++ point of view, and change
let a = []; for (let i = 0; i < 10; i++) { a.push(function () { return i; }); } for (let j in a) { assert(aj === j); }
into
let a = []; { let i = 0; for (; i < 10; i++) { a.push(function () { return i; }); } }
then the assert-loop will have to change:
for (let j in a) { assert(aj === 10); }
but that's what you asked for. for(let ...;;) is a special form.
On Thu, Jan 19, 2012 at 8:20 PM, Axel Rauschmayer <axel at rauschma.de> wrote:
Given that this desugaring will only kick in if a closure leaves the loop (right?), this is a case of automatically doing the right thing (and only if it’s warranted).
Yes kids, this means we are going with MarkM's lambda desugaring from:
The difference between this behavior and the current behavior should only be observable when capturing the environment with a closure (or maybe with a direct eval), so in many cases nothing changes.
The downside, if it is a downside, is that if you take a literal C/C++ point of view, and change
let a = []; for (let i = 0; i < 10; i++) { a.push(function () { return i; }); } for (let j in a) { assert(aj === j); }
into
let a = []; { let i = 0; for (; i < 10; i++) { a.push(function () { return i; }); } }
then the assert-loop will have to change:
for (let j in a) { assert(aj === 10); }
but that's what you asked for. for(let ...;;) is a special form.
Right. The choice between explicitly copying and explicitly sharing. The former being awkward and sharing still being available makes it look like the right decision.
On Thu, Jan 19, 2012 at 11:02 PM, Brendan Eich <brendan at mozilla.org> wrote:
Yes kids, this means we are going with MarkM's lambda desugaring from:
Is there a version of this desugaring that deals with recursive bindings in the initializer expression of the loop?
In my post (esdiscuss/2008-October/007826), I used an example like:
for (let fn = function() { ... fn(); ...};;)
There are other, related cases, like:
for (let [i, inc] = [0, function() {i++;}]; i < n; inc()) ...
In that earlier post, I wrote that "the modifications [to MarkM's desugaring] needed to make these work are pretty straightforward," though I can't recall what I had in mind at the time.
Waldemar's option (above) solves the recursive function case, but not the local-inc case. Even as the loop rebinds i and inc, the latter will continue to refer to (and increment) the initial binding of i.
Jon Zeppieri wrote:
Is there a version of this desugaring that deals with recursive bindings in the initializer expression of the loop?
How about something like this? (given for (let <varName> = <initExpr>; <testExpr>; <updateExpr>) { <body> } )
{ let <varName> = <initExpr>; while(true) { if (!<testExpr>) { break breakTarget; } let <tempVar> = <varName>; { // There might be a better way to copy values to/from shadowed variables // (using temporaries seems a bit weak) let <varName> = <tempVar>; continueTarget: { <body> } <tempVar> = <varName>; } <varName> = <tempVar>; <updateExpr>; } }
That way, all of the variable references in initExpr, testExpr and updateExpr refer to a singular copy and all of the variable references in body refer to the iteration-scoped ones.
So, looking at your example:
for (let [i, inc] = [0, function() {i++;}]; i < n; inc()) ...
I think it now has the desired behaviour. However, people calling inc from inside the body will still be surprised. I think solving that probably requires something more advanced than a desugaring, as it means the loop variables captured by that function (or, alternatively, ones captured inside the body) need to point at different variables at different times.
There's also an abstraction leakage if one breaks in the body, in that the inner <varName> doesn't get copied to the outer one. All in all,
not a great desugaring, but I thought it might be worth offering.
Maybe disallowing capture in the for (let ...;...;...) head would be easier.
, Grant Husbands.
A couple of remarks/questions...
On 20 January 2012 01:40, Waldemar Horwat <waldemar at google.com> wrote:
Allen: Do top-level let and const create properties of the global object? DaveH (channeling Andreas): No, but functions do.
If that is referring to me then there might have been a misunderstanding. I don't think I ever suggested making a distinction between different forms of static bindings. That would be terrible. :)
Sam: If they don't then the T-shirt Erik is currently wearing wouldn't work. Many agreed that we can't break the T-shirt.
Let me guess: that T-shirt is saying "let is the new var"?
DaveH: What if there are duplicate top-level bindings? MarkM: Top-level let should behave as much as possible the same as concatenated scripts.
There are some serious issues lurking here. I would like to float another idea for reforming the top-level, but I'll do so in a separate post.
Also, "function (e) {let e;}" should always be an error.
Is there a good reason to do this? It would be an unnecessary irregularity with block scoping, and seems like overly nanny-ish (in stark contrast to other parts of the language).
Discussion about scope of for-bindings. for (var x = ...;;) {...} will, of course, retain ES1 semantics. for (let x = ...;;) {...} Allen: This will behave as in C++: x is bound once in a new scope immediately surrounding just the for statement. DaveH: Strangely enough, this creates a new x binding in Dart at each iteration.
Why strange?
[...] Those opposed earlier to new-binding-per-iteration hop back onto the fence. Waldemar, Brendan, and DaveH hop off the fence to now support it, as it will cure an annoying gotcha in practice. Looks like we have support for it now.
I'm happy to hear that. Given lexical closures, I think it clearly is the far superior semantics. Just need to get the V8 implementation in line...
Andreas Rossberg wrote:
On 20 January 2012 01:40, Waldemar Horwat<waldemar at google.com> wrote:
Also, "function (e) {let e;}" should always be an error.
Is there a good reason to do this? It would be an unnecessary irregularity with block scoping, and seems like overly nanny-ish (in stark contrast to other parts of the language).
+1. I see no point why let e; should not shadow argument e here.
On 20 January 2012 09:22, Herby Vojčík <herby at mailbox.sk> wrote:
+1. I see no point why let e; should not shadow argument e here.
I do. It is a virtual certainty that this form was used accidentally by the developer, which indicates a flaw in the developer's thinking -- probably due to cut-paste/refactor code having a variable name collision. It should be an early error/warning, just like it is in C.
On 19 January 2012 23:02, Brendan Eich <brendan at mozilla.org> wrote:
Yes kids, this means we are going with MarkM's lambda desugaring from:
mail.mozilla.org/**pipermail/es-discuss/2008-**October/007819.htmlesdiscuss/2008-October/007819
So any closures formed in the body of such a for(let...;...;...) loop will capture the binding created afresh for that iteration.
Thank you, Lord! \o/ Can I get a Hallelujah? \o/
for (i=0; i < alerts.length; i++) { setTimeout(function(i) { return function() { m.add(alerts[i]) } }(i), (i+1) * 100000); }
Here ^^ is a real loop I wrote last week, weeping the entire time.
So any closures formed in the body of such a for(let...;...;...) loop will capture the binding created afresh for that iteration.
Thank you, Lord! \o/ Can I get a Hallelujah? \o/
for (i=0; i < alerts.length; i++) { setTimeout(function(i) { return function() { m.add(alerts[i]) } }(i), (i+1) * 100000); }
Here ^^ is a real loop I wrote last week, weeping the entire time.
I agree. If you are willing to add two more lines, you can make the code a little more readable:
for (i=0; i < alerts.length; i++) {
(function (i) {
setTimeout(function() { m.add(alerts[i]) }, (i+1) * 100000);
}(i));
}
On Jan 20, 2012, at 6:22 AM, Herby Vojčík wrote:
Andreas Rossberg wrote:
On 20 January 2012 01:40, Waldemar Horwat<waldemar at google.com> wrote:
Also, "function (e) {let e;}" should always be an error.
Is there a good reason to do this? It would be an unnecessary irregularity with block scoping, and seems like overly nanny-ish (in stark contrast to other parts of the language).
+1. I see no point why let e; should not shadow argument e here.
In general, the binding rules for function parameters were decided at the Nov. 2011 meeting (see Nov 16 meeting notes):
MarkM: Two-scope model (one scope for parameters, an independent inner scope for let, const, and var bindings). This model is upwards-compatible with ES5.1 strict because the latter disallows shadowing of a parameter by a binding in function scope.
Allen: Two-scope model, but with inner scope prohibited from shadowing parameters. MarkM: Likes this. Any program that is accepted works with either of the two-scope model intuitions.
Whether you view this has two scopes with static semantic rules that prohibit inner declarations from shadowing or a single scope with appropriate static semantic rules that prevent redeclaration of formals, the effect is essentially the same. The current specification draft actually uses a single environment record and appropriate static semantic rules. However you model it in terms of scopes, the intent is that the function formal parameters and the top level declarations are treated as a single naming contour for the purposes of allowing or disallowing duplicate declarations.
Also we have the following rules such such naming contours: We don't allow duplicate let declarations for the same name. We don't allow a let binding and a var declarations for the same name. There may be multiple var declarations for the same name. They all refer to the same binding.
Given those rules, how to we think about formal parameters? If they are equivalent to let declarations, then the first rule would disallow function(d) {let e}. If they are equivalent to var declarations, then the second rule would disallow that function.
On Jan 20, 2012, at 7:13 AM, Wes Garland wrote:
On 20 January 2012 09:22, Herby Vojčík <herby at mailbox.sk> wrote:
+1. I see no point why let e; should not shadow argument e here.
I do. It is a virtual certainty that this form was used accidentally by the developer, which indicates a flaw in the developer's thinking -- probably due to cut-paste/refactor code having a variable name collision. It should be an early error/warning, just like it is in C.
This was essentially the conclusion that was reached when this was discussed at the Nov. TC39 meeting.
Allen Wirfs-Brock wrote:
On Jan 20, 2012, at 6:22 AM, Herby Vojčík wrote:
+1. I see no point why let e; should not shadow argument e here.
In general, the binding rules for function parameters were decided at the Nov. 2011 meeting (see Nov 16 meeting notes):
MarkM: Two-scope model (one scope for parameters, an independent inner scope for let, const, and var bindings). This model is upwards-compatible with ES5.1 strict because the latter disallows shadowing of a parameter by a binding in function scope.
Allen: Two-scope model, but with inner scope prohibited from shadowing parameters. MarkM: Likes this. Any program that is accepted works with either of the two-scope model intuitions.
Whether you view this has two scopes with static semantic rules that prohibit inner declarations from shadowing or a single scope with appropriate static semantic rules that prevent redeclaration of formals, the effect is essentially the same. The current specification draft actually uses a single environment record and appropriate static semantic rules. However you model it in terms of scopes, the intent is that the function formal parameters and the top level declarations are treated as a single naming contour for the purposes of allowing or disallowing duplicate declarations. ...
"Single scope, args are lets" view is making sense of this. Ok, thanks.
On Fri, Jan 20, 2012 at 9:57 AM, Herby Vojčík <herby at mailbox.sk> wrote:
"Single scope, args are lets" view is making sense of this. Ok, thanks.
Another case together with this one seems to force us into "Single scope, args are vars":
function foo(e) { var e ... }
The "var e" is currently accepted in both strict and non-strict as a redundant declaration of the same variable, no shadowing or error. We can't break this. And we can't explain it if params are "let" bindings.
If it turns out to be practically backwards compatible, we would like to explain "} catch (e) {" as a let binding of "e", leading to a simpler explanation of its block-local scope. The hard case is
} catch (e) { var e ... }
which would have to become an error. We don't yet know if this new breakage would create actual problems in practice.
On 20 January 2012 18:26, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:
On 20 January 2012 01:40, Waldemar Horwat<waldemar at google.com> wrote:
Also, "function (e) {let e;}" should always be an error.
Is there a good reason to do this? It would be an unnecessary irregularity with block scoping, and seems like overly nanny-ish (in stark contrast to other parts of the language).
In general, the binding rules for function parameters were decided at the Nov. 2011 meeting (see Nov 16 meeting notes):
MarkM: Two-scope model (one scope for parameters, an independent inner scope for let, const, and var bindings). This model is upwards-compatible with ES5.1 strict because the latter disallows shadowing of a parameter by a binding in function scope.
Allen: Two-scope model, but with inner scope prohibited from shadowing parameters. MarkM: Likes this. Any program that is accepted works with either of the two-scope model intuitions.
Whether you view this has two scopes with static semantic rules that prohibit inner declarations from shadowing or a single scope with appropriate static semantic rules that prevent redeclaration of formals, the effect is essentially the same. The current specification draft actually uses a single environment record and appropriate static semantic rules. However you model it in terms of scopes, the intent is that the function formal parameters and the top level declarations are treated as a single naming contour for the purposes of allowing or disallowing duplicate declarations.
Here is a simple model: a function expression introduces one local scope(*), which contains the parameters and the var variables hoisted from its body (as in ES5). The function is evaluated by evaluating its body as a block (which it is, syntactically).
This is a simpler, more compositional rule with fewer special cases. In effect, you have two scopes, but there is nothing special at all about the inner one. In particular, var-bound vars are hoisted out of this block like they are hoisted out of inner blocks.
This is fully backwards compatible, AFAICS.
(*) Ignoring the extra scope for the optional function name.
On 20 January 2012 18:28, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:
On Jan 20, 2012, at 7:13 AM, Wes Garland wrote:
On 20 January 2012 09:22, Herby Vojčík <herby at mailbox.sk> wrote:
+1. I see no point why let e; should not shadow argument e here.
I do. It is a virtual certainty that this form was used accidentally by the developer, which indicates a flaw in the developer's thinking -- probably due to cut-paste/refactor code having a variable name collision. It should be an early error/warning, just like it is in C.
This was essentially the conclusion that was reached when this was discussed at the Nov. TC39 meeting.
How is
function(x) { let x }
any different in this respect from
{ let x { let x } }
? The same argument can be made in either case. The latter is allowed, the former isn't. In both cases, a block-local let shadows a variable from outer scope.
Mark S. Miller <mailto:erights at google.com> January 20, 2012 10:15 AM On Fri, Jan 20, 2012 at 9:57 AM, Herby Vojčík <herby at mailbox.sk <mailto:herby at mailbox.sk>> wrote:
"Single scope, args are lets" view is making sense of this. Ok, thanks.
Another case together with this one seems to force us into "Single scope, args are vars":
function foo(e) { var e ... }
The "var e" is currently accepted in both strict and non-strict as a redundant declaration of the same variable, no shadowing or error. We can't break this. And we can't explain it if params are "let" bindings.
Exactly -- sorry I didn't raise this yesterday. Allen, IIRC we've discussed it. This was the reason ES4 equated let and var at top of function body or Program production (but that was in the bad old days).
If it turns out to be practically backwards compatible, we would like to explain "} catch (e) {" as a let binding of "e",
ES5 doesn't include "let" but essentially specifies this, and engines do it (those that support 'let' use exactly the same machinery).
leading to a simpler explanation of its block-local scope. The hard case is
} catch (e) { var e ... }
which would have to become an error. We don't yet know if this new breakage would create actual problems in practice.
Pretty sure we can break this. We should.
Andreas Rossberg <mailto:rossberg at google.com> January 20, 2012 10:17 AM
Here is a simple model: a function expression introduces one local scope(*), which contains the parameters and the var variables hoisted from its body (as in ES5). The function is evaluated by evaluating its body as a block (which it is, syntactically).
This is a simpler, more compositional rule with fewer special cases. In effect, you have two scopes, but there is nothing special at all about the inner one. In particular, var-bound vars are hoisted out of this block like they are hoisted out of inner blocks.
This is fully backwards compatible, AFAICS.
(*) Ignoring the extra scope for the optional function name.
+1. I do not see how we can make parameters be let-bound, given function f(x) { var x; ... } being allowed in ES5 non-strict and strict.
On Jan 20, 2012, at 10:22 AM, Brendan Eich wrote:
Mark S. Miller <mailto:erights at google.com> January 20, 2012 10:15 AM On Fri, Jan 20, 2012 at 9:57 AM, Herby Vojčík <herby at mailbox.sk <mailto:herby at mailbox.sk>> wrote:
"Single scope, args are lets" view is making sense of this. Ok, thanks.
Another case together with this one seems to force us into "Single scope, args are vars":
function foo(e) { var e ... }
The "var e" is currently accepted in both strict and non-strict as a redundant declaration of the same variable, no shadowing or error. We can't break this. And we can't explain it if params are "let" bindings.
Exactly -- sorry I didn't raise this yesterday. Allen, IIRC we've discussed it. This was the reason ES4 equated let and var at top of function body or Program production (but that was in the bad old days).
I think it did come up, which is why I would actually apply the "Single scope, args are vars" (which can not be redeclared via let) rule.
In fact formals parameters are neither let or var bindings (and the specification doesn't even distinguish environment record bindings in that manner). Classic non-strict arguments are pretty var like, but strict mode forbids multiple formals with the same name ( a let-like characteristic) and we have agreed that new syntactic forms for formal (eg destructuring) will also preclude multiple declarations of the same name even in non-strict contexts.
If it turns out to be practically backwards compatible, we would like to explain "} catch (e) {" as a let binding of "e",
ES5 doesn't include "let" but essentially specifies this, and engines do it (those that support 'let' use exactly the same machinery).
leading to a simpler explanation of its block-local scope. The hard case is
} catch (e) { var e ... }
which would have to become an error. We don't yet know if this new breakage would create actual problems in practice.
Pretty sure we can break this. We should.
From the meeting, this was my understanding of how we will proceed. All of the breaking changes we discussed in the context of enabling ES6 features into non-strict code are subject to reconsideration if we discover actual web breakage.
On Jan 20, 2012, at 10:19 AM, Andreas Rossberg wrote:
On 20 January 2012 18:28, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:
On Jan 20, 2012, at 7:13 AM, Wes Garland wrote:
On 20 January 2012 09:22, Herby Vojčík <herby at mailbox.sk> wrote:
+1. I see no point why let e; should not shadow argument e here.
I do. It is a virtual certainty that this form was used accidentally by the developer, which indicates a flaw in the developer's thinking -- probably due to cut-paste/refactor code having a variable name collision. It should be an early error/warning, just like it is in C.
This was essentially the conclusion that was reached when this was discussed at the Nov. TC39 meeting.
How is
function(x) { let x }
any different in this respect from
{ let x { let x } }
? The same argument can be made in either case. The latter is allowed, the former isn't. In both cases, a block-local let shadows a variable from outer scope.
/Andreas
This is a suability issue. Languages with c-like syntax seem to generally disallow top level re-declarations of formal parameters, even when they other support block scoped declarations. Presumably because it is assume that shadowing probably not the user intent in most such situations. I researched this last year and captured it in a email exchange I had with Brendan:
On Jun 8, 2011, at 11:23 AM, Allen Wirfs-Brock wrote:
On Jun 8, 2011, at 10:48 AM, Brendan Eich wrote:
On Jun 8, 2011, at 10:28 AM, Allen Wirfs-Brock wrote:
Does the semantics have any utility:
I don't believe there is any utility in:
function (x) {let x=; ...}
it simply makes the formal x inaccessible. In all probability this is really a coding or refactoring error.
That's not the case that arises from the let* semantics we (almost, you demurred after the meeting) agreed on last September at Mozilla:
function (x) {foo(x); let x = bar(); baz(x);}
Here (and imagine it is a bigger function), the let semantics from last fall would make a new scope at the let x, as if there were an explicit { before it and one to balance at the end.
Users of C++ would be surprised, I think, if they couldn't write something like this. Not that C++ users get undue weight, but you get my point: it depends on what language(s) you are coming from.
According to the C++ specification rule I cited in my message the C++ equivalent to the above function would be an error because it redeclares a parameter name at the top level. Throw an extra level of { } around the function body and the results would be different. It would also be an error in Java and C#.
I think there is strong precedent and good usability reasons for treating the formal parameter list and the top-level function scope as if they were the same "lexical name space". EG, the top level function body is not allowed to shadow (or redeclare) formal parameters. Also, there are backwards compatibility requirements (even in strict mode) that function top level var statements and function declarations are able to change the values of formal parameters. These are defined as SetMutableBinding operations not as creating new bindings.
This is a recurring discussion. The discussion always seems to resolve (perhaps with some unhappy acquiesce) that we want to follow the C++/Java/C# (and other similar language) precedent adjusted to deal with legacy var and function semantics.
On Fri, Jan 20, 2012 at 7:25 AM, Grant Husbands <esdiscuss at grant.x43.net> wrote:
Jon Zeppieri wrote:
Is there a version of this desugaring that deals with recursive bindings in the initializer expression of the loop?
How about something like this? (given for (let <varName> = <initExpr>; <testExpr>; <updateExpr>) { <body> } )
{ let <varName> = <initExpr>; while(true) { if (!<testExpr>) { break breakTarget; } let <tempVar> = <varName>; { // There might be a better way to copy values to/from shadowed variables // (using temporaries seems a bit weak) let <varName> = <tempVar>; continueTarget: { <body> } <tempVar> = <varName>; } <varName> = <tempVar>; <updateExpr>; } }
That way, all of the variable references in initExpr, testExpr and updateExpr refer to a singular copy and all of the variable references in body refer to the iteration-scoped ones.
It doesn't satisfy Desirable Property #3 from the previously cited email:
- The rewrite rules are the same, regardless of whether it's a "for (var ...)" or a "for (let ...)" loop.
But that's the least important property.
So, looking at your example:
for (let [i, inc] = [0, function() {i++;}]; i < n; inc()) ...
I think it now has the desired behaviour. However, people calling inc from inside the body will still be surprised.
Yeah, that's a problem.
I think solving that probably requires something more advanced than a desugaring, as it means the loop variables captured by that function (or, alternatively, ones captured inside the body) need to point at different variables at different times.
That's my suspicion, as well, and I'm curious whether this affects TC39 members' opinion. It's not entirely clear from Brendan's email what caused him, Waldemar, and David Herman to "hop off the fence" in support of the fresh-binding-per-iteration approach, but it sounds to me like they were initially concerned about needing to specify a complicated semantics and were persuaded by MarkM's argument that the problem could be solved syntactically.
There's also an abstraction leakage if one breaks in the body, in that the inner <varName> doesn't get copied to the outer one. All in all, not a great desugaring, but I thought it might be worth offering.
Maybe disallowing capture in the for (let ...;...;...) head would be easier.
I still think there's something misleading about taking a loop with an imperative update and re-binding behind the scenes, despite the fact that the problem it's trying to solve is definitely a real problem (I've been bitten by it myself). It's one thing if the difference really isn't observable except in the case where a closure captures the iteration variable (as Sam suggests), since it's hard to imagine anyone wanting the current binding behavior in that case. But the recursive binding cases make me a bit uneasy.
On Fri, Jan 20, 2012 at 5:08 PM, Jon Zeppieri <zeppieri at gmail.com> wrote:
It's one thing if the difference really isn't observable except in the case where a closure captures the iteration variable (as Sam suggests), since it's hard to imagine anyone wanting the current binding behavior in that case. But the recursive binding cases make me a bit uneasy.
Heh. Of course, the recursive binding cases are cases where a closure captures the iteration variable... The distinction I was trying to draw is between the normal case, where the binding is captured in the body, and the oddball cases I've mentioned, where it's captured in the loop initializer.
On 01/19/2012 10:51 PM, Jon Zeppieri wrote:
On Thu, Jan 19, 2012 at 11:02 PM, Brendan Eich<brendan at mozilla.org> wrote:
Yes kids, this means we are going with MarkM's lambda desugaring from:
Is there a version of this desugaring that deals with recursive bindings in the initializer expression of the loop?
In my post (esdiscuss/2008-October/007826), I used an example like:
for (let fn = function() { ... fn(); ...};;)
There are other, related cases, like:
for (let [i, inc] = [0, function() {i++;}]; i< n; inc()) ...
In that earlier post, I wrote that "the modifications [to MarkM's desugaring] needed to make these work are pretty straightforward," though I can't recall what I had in mind at the time.
Waldemar's option (above) solves the recursive function case, but not the local-inc case. Even as the loop rebinds i and inc, the latter will continue to refer to (and increment) the initial binding of i.
Yeah, I know about that. If the updater is something like i++, you want the closures to capture the value of the i before the updater runs. I didn't bring up that case (and we didn't discuss it during the meeting) because, if we choose to do this approach, its resolution is pretty straightforward and we were short on time. I recall seeing Mark's desugaring that already handles it. We'll revisit the details in the future.
Waldemar
On Fri, 2012-01-20 at 19:19 +0100, Andreas Rossberg wrote:
How is
function(x) { let x }
any different in this respect from
{ let x { let x } }
In the former, there is no part of the body in which the parameter is visible (modulo arguments, of course). I can see how that might be confusing if the "let" appears later in the function:
function(x) { bar(x) ... ... let x = 2; ... }
Of course, the same argument applies to blocks, but in that case there is more syntactic uniformity.
Andy
On 20 January 2012 20:51, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:
This is a recurring discussion. The discussion always seems to resolve (perhaps with some unhappy acquiesce) that we want to follow the C++/Java/C# (and other similar language) precedent adjusted to deal with legacy var and function semantics.
Yes, I see the argument. Not sure I'm convinced by it, though, given that blocks already have significantly different scoping rules than in other curly braces languages. Moreover, it wouldn't change anything that was legal in these other languages, it would just allow more.
But it's a minor point.
On 23 January 2012 10:12, Andy Wingo <wingo at igalia.com> wrote:
On Fri, 2012-01-20 at 19:19 +0100, Andreas Rossberg wrote:
How is
function(x) { let x }
any different in this respect from
{ let x { let x } }
In the former, there is no part of the body in which the parameter is visible (modulo arguments, of course). I can see how that might be confusing if the "let" appears later in the function:
function(x) { bar(x) ... ... let x = 2; ... }
Of course, the same argument applies to blocks, but in that case there is more syntactic uniformity.
Not sure what "syntactic uniformity" you are referring to. This is a
problem with the block-scoping semantics in general (which,
unfortunately, seems unavoidable in JS). It makes no difference
whether the outer x is bound by let', by
catch', by var', by
module', or anything else. Except as an argument of `function' (and
only if it is directly enclosing), for which we plan to introduce a
special case. This irregularity is what I was wondering about.
Jan 28 Meeting Notes
John Neumann (JN), Allen Wirfs-Brock (AWB), Yehuda Katz (YK), Eric Ferraiuolo (EF), Erik Arvidsson (EA), Rick Hudson (RH), Matt Sweeney (MS), Dmitry Soshnikov (DS), Sebastian Markbage (SM), Ben Newman (BN), Jeff Morrison (JM), Reid Burke (RB), Waldemar Horwat (WH), Doug Crockford (DC), Mark Miller (MM), Brian Terlson (BT), Luke Hoban (LH), Andreas Rossberg (ARB), Istvan Sebestyen (IS), Niko Matsakis (NM), Brendan Eich (BE), Rick Waldron (RW), Sam Tobin-Hochstadt (STH), Simon Kaegi (SK)
IS: Talk about the royalty free task group
JN: Approved, 9 in favor. 0 opposed. 0 abstains. We are now operating as a Royalty Free Task Group
JN: Netflix and Apple haven't returned the paper work.
IS: Neither from Brown University. (and a bunch of other universities that are not active any more)
Agenda
JN: Agenda approved tc39/agendas/blob/master/2014/01.md
JN: Minutes from Nov meetings also approved. (rwaldron/tc39-notes/tree/master/es6/2013-11)
Spec Status update
AWB: Latest draft (Rev22) is the "almost feature complete" version. (Discussion about process troubles). Spec now uses a master document and is split into multiple files.
AWB: Still some work to do on Direct Proxies. Update spec for C-style for-let. Loaders and Realms are integrated into the spec draft. Lots of review needed.
EA: Standard modules were deferred at last F2F
LH: We agreed on globally reachable names for all pre-modules APIs last September. New names for module loaders APIs need similar design.
AWB: Loader and Realm are speced as %Loader% and %Realm% since we haven't talked about their public names.
DH: Where does Reflect go?
AWB: Use a global.
DH: Realm can go in Reflect since it is a very reflective thing.
DH: We can probably defer System too.
YK: We need an entry point and a global named System seems to be good.
DH: Loader can go in Reflect too.
AWB: Need to update the spec draft to match the scoping rules we agreed to before.
Resolution
Aside on detecting Module vs. Script (see
esdiscuss.org/topic/detecting-js-language-mode-for-tools)
Debate about whether it's required (partial agreement that it is since they are clearly distinct)
WH: Even though they're distinct, doesn't mean that they must be ambiguous with each other at the source text level. We could easily say that a module has to start with some syntax that designates it as a module.
AWB: Spec doesn't necessarily need to address this (why?) but we should consider setting the direction here. If we're fine with the community coming up with something here we can lean on that too.
LH: This process has to happen, there will be lots of solutions, we might not pick the best one.
Potential solutions:
- YK: Bower uses metadata for packages that say they're ES6 module
- DH: Possibly do nothing, we live in this world already today
- DH: Come up with some kind of syntactical distinction
- DH: This sucks, modules should not require additional boilerplate to be valueable
- Possibly use file extensions...
Conclusion/resolution:
- DH to do the work?
Task and Tasks Queues
Postponed until tomorrow when Raf is here.
Process for ratifying ES6?
LH: We have now effectively met the "feature complete draft" requirement we were targetting. Are there any process requirements this group is placing on progressing the spec to ratifica
BE: Have nothing, same as ES5. (Discussion about whether we can be strict)
LH: For example, do we have "multiple compatibile implementations" requirements? Or "test262 coverage" requirements? Our ES7 process proposal has these, but do we want/need some limitied version of this for ES6?
AWB: We just need to ship it and get to the stricter process for ES7.
MM: We can always postpone features to ES7 if they seem to be problematic.
BE: For example, there is unlikely to be an implementation of proper tail calls before we send ES6 to the GA, then to ISO. I don't think we should defer them on that basis, but it's a fact. We should not slip ES6's schedule.
LH: If by the time we ratify ES7 and there are still ES6 features that have not yet been implemented by anyone, we should re-evaluate if we can remove them.
Resolution
The commitee is putting no blocking requirements of implementations or tests on standardization of ES6.
Concise methods and Enumerability
YK: People have object literals today and use these objects with for-in loops to find the properties and if they change to non enumerable consise methods things will break.
AWB: Concise methods were initially non-enumerable. This was to match the built-in classes, like Date, Array etc. One possibility is to make methods in classes non enumerable but concise methods in object literals enumerable.
RW: The same issue happens when people use object literals as the prototype.
AWB: Should Map and Set methods be enumerable then?
RW: The spec should be consistent with itself.
WH: User-defined classes should be consistent with built-in classes. Classes are new in ES6. The question is whether it's the class that turns off enumerability or the concise method that turns off enumerability.
WH: My preference is for the consise method syntax to turn off enumerability. In the rare cases that you want an enumerable method in a prototype, you can define it the longer way.
YK: Refactoring should be simple and not have side effects like these.
RW: hasOwnProperty solves the problem of filtering out class methods inherited from the prototype, so we don't need to make them non-enumerable.
BE: people don't use hasOwnProperty
YK: enumerability is broken, we should not discuss the Platonic ideal form of enumerability
BE: According to Neo-Platonic Mystics, the material world was created by the evil Demiurge, not by Sophia (wisdom). Enumerability and 'for-in' are from the Demiurge.
BE: Enumerating options: * Concise methods and class methods are enumerable * Current es6 draft state * Split the difference, concise methods enumerable, class methods non-enumerable. * can't refactor between es5 object literal and es6 class/concise methods depending on which is non-enumerable * Make both non-enumerable (Waldemar supports) * same refactoring hazard, possibly not desirable * Some tilde-based or better syntax to allow developers to pick, but go with option 1
YK: Hope that we can use annotations in ES.Future that can control this kind of details.
BE: Agree, so fourth option above.
YK/LH: High bar to make a change, does this meet the bar?
Conclusion/Resolution
- Status quo. Keep concise methods enumerable.
More on toMethod
AWB: Function.prototype.toMethod(superBinding, methodName = undefined) Footgun to put this on Function.prototype.
MM: potential suprise: in the absence of toMethod, super's interpretation can't change, but now people have to account for possibility of shifting interpretation, which requires them to know about toMethod (not sure if I'm getting this right- BN)
AWB: The footgun is that we do not propagate any properties.
AWB: Suggest moving toMethod to Reflect
DH: Needs to be renamed then.
?: Suggests renaming to bindSuper.
WH: We've discussed all of this before and reached consensus. bindSuper is a bad name because it intentionally doesn't commute with bind.
WH: [reviews consensus from past meeting]
AWB: expect people to define Object.defineMethod in terms of toMethod, with copying of properties
DS: do we also need toStaticMethod?
AWB: no, you can just use toMethod with the constructor function as the superBinding / home object
BN: are static/class methods inherited?
AWB: yes
AWB: should we copy .name and/or .length to the new function object?
MM: use bind as a precedent to decide what to copy (mixed messages though: bind does copy .length, minus the number of curried arguments, and (in SpiderMonkey at least) copies the .name, though V8 gives the bound function an empty string .name)
AWB: What should happen if toMethod is called on a non ECMAScipt function object (built-in)
MM: How about just returning a clone of the function. You could even even delegate in a similar way as bind.
AWB: Only allow toMethod on unbound methods?
MM: to preserve possibility of transparent monkey-patching, either make toMethod return something that can't be toMethod-ed again, or allow built-in (non-ECMAScript Function Object) functions to be cloned, which requires an additional path in the internal CloneMethod operation (because it currently asserts that the clonee is an ESFO)
Conclusion/Resolution
- Allen to take it back to the lab. To get it to work with bound
functions and built-ins.
- Make it match old concensus
func.bind().toMethod(...)
should throw - Does not work on proxies
- Make it match old concensus
Clz (count leading zeros)
WH: Don't like deliberately introducing anachronisms a la 1900-origin getYear into the language. Would prefer to have it be origin-0 instead of origin-32 (i.e. return 0 instead of 32 when called on 0) to avoid hardwiring a machine word size. However, understand that we want this to compile to an efficient low-level primitive, so it would still have the toUInt32 as part of its semantics. In that case we should call it clz32 instead of clz so that later we can do clz64 (that would call a future toUInt64) or other variants.
BE: Want it to map to one single machine instruction
BE: Mislocated, should be on Math
BE: (missed the third point)
BE: CLZ - for cases when you're doing DSP-level hacking, and want to count the number of populated bits. Also important for native-to-js compilers, there is an intrinsic for this in GCC and Clang. BE: Math.clz32 wins.
Conclusion/Resolution
- Rename to Math.clz32 (rename and move from Number.prototype)
Array.from
AWB: What should happen with Array.from(undefined)
?
EA: Array.from
is a likely replacement for
Array.prototype.slice.call
and the array generics do ToObject
.
AWB: Array with holes would lead to to a dense array.
YK: Want to keep the holes.
BE: "Holes are from the devil"
Conclusion/Resolution
Keep as spec'ed.
* Array.from
will throw on undefined
and null
* Array.from
will return []
for 3
* Array.from([0, , 2])
=> [0, undefined, 2]
Test 262
BT: Up on GitHub. tc39/test262. Conversion from Mercurial done by Brandon Benvie.
BT: AttendedTest the web forward. Got a lot of PR (22).
BT: Pending contributor guidelines.
BT: Going to work on style guidelines since the PRs are inconsistent.
IS: Getting CLA working is highest prioroty.
BT: Do we need any test coverage before approving ES6?
BT: For ES7 we agreed that we need tests before final spec.
BT: Instead of using numbered section plan to use the HTML anchor names from the HTML version of the spec.
Yield and its precendence
Code Samples: gist.github.com/lukehoban/8678463
LH: Presents code samples. All but "yield 1+2" seem strange. Any time you have a generator that pumps values in you want good expression semantics.
WH: Points to yield 1+2 alternatives in LH's code samples; one makes it mean (yield 1)+2, the other makes it mean yield(1+2). Strongly prefers the latter.
BE: Have to make a choice that yield should be high precedence or low precedence. yield x + y must be yield(x + y) without parens, the rest follows by the grammar.
LH: concede
:: conversation about whether implementing iterators is more common or taskjs-like scenarios are more common ::
BN: Status quo causes more errors but errors encourage
parenthesization, and enables yield 1 + 2
to yield the value 3
LH: For the async use case, important to have high precendence, but
willing to concede that yield
should remain low precenedence due to
iterators use cases. Async use cases could have new "await" syntax
with high precendence.
YK: task.js requires (yield a) + (yield b) paren style
BE: revenge of Lisp, you get used to it
Conclusion/Resolution
- Status Quo
More generators (Ben)
See issue here: tc39/agendas#25
DH: Intention was for generators to be composable.
BN: Proposal: generator with yield* doesn't throw when receiving a value
DH: Breaks correspondance between yield* and for-of desugaring. Also... wrappers are not equivalent unless both wrapper and wrapped are newborn.
BN: Can be fixed... but is hairy. Presents updated wrapper code... Proposal is that we remove the type error for passing in a value to an unborn generator. Then, if the first yield we encounter is a yield *, pass in the value that was passed to the unborn generator. :: Concerns with proposal (please fill?) ::
DH: Possibly other alternatives to fix this?
WH: There are two problems here: 1. A function* can't capture the first value passed to the 'next' that invoked it. Instead, it currently requires it to be undefined. 2. No way to pass an initial 'next' value to yield*. This means that manually doing the first yield followed by a yield* wouldn't help because the problem would then reappear on the second yield.
WH: The proposal is proposing a hidden channel (a la Perl's $_) that ties 1 to 2 here. Would prefer mechanisms to do those separately and more explicitly.
BN: yield` syntax that says delegate but don't care about value?
DH: Let's think about it more...
DH: Went through the mental excercise to do an implicit yield upon calling the generator. Leads to a lot of other issues.
function*() first {
return yield* push(first, delegate);
}
Concensus/Resolution
- BN: Have to go back and think more about this. Maybe a helper function can be created.
ECMA-404 and IETF interactions
AWB: IETF is not comfortable referencing ECMA.
IS: IETF includes ECMA-404 as an informative reference (?)
AWB: Proposed doing a second edition if IETF wanted to work with ECMA. :: Discussion about IETF participation, general dissatisfaction with the process and end result :: See www.ietf.org/mail-archive/web/json/current/threads.html#02131 and look for "R S" (Rob Sayre) fighting the good fight
Jan 29 Meeting Notes
John Neumann (JN), Allen Wirfs-Brock (AWB), Yehuda Katz (YK), Eric Ferraiuolo (EF), Erik Arvidsson (EA), Rick Hudson (RH), Matt Sweeney (MS), Dmitry Soshnikov (DS), Sebastian Markbage (SM), Ben Newman (BN), Jeff Morrison (JM), Reid Burke (RB), Waldemar Horwat (WH), Doug Crockford (DC), Mark Miller (MM), Brian Terlson (BT), Luke Hoban (LH), Andreas Rossberg (ARB), Istvan Sebestyen (IS), Niko Matsakis (NM), Brendan Eich (BE), Rick Waldron (RW), Sam Tobin-Hochstadt (STH), Rafael Weinstein (RWS), Dmitry Lomov (DL), Niko Matsakis (NM), Simon Kaegi (SK), Kevin Reid (KR)
Function in Blocks in non strict mode.
(Ask Brian for slides)
BT: In ES6 draft in appendix B (since functions in block are not in ES5 but implemented)
BT: IE11 shipped with function in block in non strict mode.
BT: Hoists across let blocks
AWB: If you start using a let then you'll get an error. Since old code
does not use let
.
LH: If the code falls out of the known patterns you hit a rough edge and then it is better to get an error than undefined behavior.
WH: Concerned about expanding past the minimal crazy intersection semantics we agreed to in the past. The proposal expands the set of cases that produce surprise captures.
WH: [on whiteboard] This is not just about eliminating errors. It will silently change the meaning of working code:
function foo() { ... 1 ... }
function bar() {
if (...) {
function foo() { ... 2 ... }
}
foo(); // Thought it would refer to the outer scope foo. Surprise!
}
function foo() { ... 1 ... }
function bar() {
if (...) {
let foo =...;
{
function foo() { ... 2 ... }
}
}
foo();
}
LH: Since 1.5% depend on the crazy behavior we have no real option.
WH: Let's limit the craziness to just the cases in the minimal intersection semantics.
BT: Allow hoisting past a let.
ARB: What was the motivation for this special case, i.e., why not drop all hoists that would normally be an error?
LH: Creates 2 bindings. The FunctionDeclaration itself mutates both the var binding and the let binding.
(function() {
{
let foo;
{
function f() {} // Why no error?
}
console.log(foo); // undefined
}
console.log(foo); // funtion foo() {}
})();
DH: If you inject a let and it shadows a var it should be a static error.
LH: In strict mode it is legal so it cannot be an error in non strict.
DH: It is consistent with a var in a block.
ARB: What happens if you have two functions
LH: You conceptually get two var bindings.
WH: That's not part of the intersection semantics. Shouldn't get any if you have two foo's in inner blocks.
YK: Writing new ES6 code in non strict should still work.
WH: It will silently do different and surprising things, as per examples above.
DH: If there is any intervening let binding do not hoist past the let.
LH: If introducing would introduce a static error. Do not introduce the var binding. [Discussion on the behavior of the new var bindings, along with whether assignment to foo updates one or both.]
WH: When are the crazy introduced var bindings initialized? At entry to outer function bar (just like ES5 inner functions in the top-level of an outer function), or at the time the inner function function foo definition is executed? Various: Set to undefined on entry to outer function. Set when inner function definition foo is executed. Various: Executing function definition updates both the let and the var bindings. Assignment updates only the let binding.
WH: [points out (and likes) warning on cases "for which the above steps are performed" in Annex B of the current draft] [Long discussion about warnings, SHOULD, and their audience]
LH: A SHOULD warning seems a reasonable addition to the proposal here.
Conclusion/resolution
- 2 bindings.
- Hoist a var binding for the FunctionDeclaration, unless it would introduce a static error (ie. hoisting past a let will not cause an error but also not create the var binding).
- Also create a let binding as per pure (strict mode) ES6 semantics. (Change from IE11 semantics). Within the scope of the let binding, assignment will only touch the let binding (ie. normal semantics).
- The var binding is only initialized at dynamic evaluation of function declaration.
- A SHOULD warning if there is a reference to any such var binding of a function
Object.observe Status Report
RWS: Suggest moving OO to the second stage. :: Approved
RWS: Wants to move OO to the third stage, which requires a spec text review.
YK: Has reviewed it already.
AWB: Might have time to review.
RWS: The plan is to ship OO in Chrome sometime around April.
AWB: Should not be a problem to advance without scrutizing the proposal. Willing to rubber stamp at this point. Since we are in a state where we are. (?)
YK: Once we are at stage 3 we are committed to not revisit.
RWS/YK to talk about task scheduling.
Conclusion/resolution
???
Post ES6 process
AWB: First step is to post the process somewhere public
AWB: Second, need a place to track the progress
AWB: Thinking we should do this on GitHub. Project TC39/meta. Master table. Or maybe 2 tables?
WH: Are we abandoning the wiki? Various: yes
WH: How do I view HTML instead of the HTML source on GitHub?
EA: We should also move the meeting notes from rwaldron/* to TC39/*
YK: We should use the GitHub API to extract the comments for keeping the paper-trail.
RWS: Agenda changes since last time 1. Add a designated reviewer. 2. At step 3 and 4 there is a requirement to get an approval from the spec editor.
RWS: Also managing spec in flight
YK: I'm going to work in that.
Do Expression
(Ask for slides from ARB)
MM: An engine can statically detect an IIFE and treat it as a do expression.
DS: Important to scope var declarations to the enclosing function rather than the do block because that's what happens in a do-while loop, and it's hard to tell if you're looking at a do block or a do-while loop.
do {
...
}
while(true);
WH, DH: Expression statements cannot start with do
to avoid
syntactic conflicts.
BE: Just like function
for FunctionExression which cannot start
ExpressionStatement.
DH: Just use a parentheses if you really need to start
ExpressionStatement with do
.
AWB: What step is this in the new process? Step 0?
ARB: Can write spec
DH: Primary reviewer.
Conclusion/resolution
- do-expressions as generailsation of block statements
- Progresses do-expressions to the next state in the new process.
Security Review for Loaders/Realms
MM: We have considered a security review for Loaders & Realms
YK: Talked about this earlier, seemed positive
STH: Concerned about definition/scope KR Gave vague definition
MM: We'd like to do the same things we did in ES5 KR Considering porting SES to ES6. DH/ STH: this is an excellent goal
MM: What's the implementation status of Loaders/Realms
DH: Unpolyfillable, YK + DH tried some things w/ iframes, didn't work
DH: That's part of why we think it's a fundamental new primitive
Conclusion/Resolution
- MM et al to port SES to ES6, contact module champions w/ results
Typed Objects
Dmitry Lomov + Niko Matsakis
NM: Not objects
WH: Likes that === compares identities, but would prefer that == compare values.
NM: THat would be dangerous since structs are mutable.
WH: In that case, how do you compare values? That's a really common thing that users will want to be able to do.
ARB: Accessing a sub struct of a struct does not allocate any object.
NM: You can stack allocate
Line = new StructType({from: Point, ...})
line = Line(...)
while ( ... ) {
foo(line.from)
}
DH: If line.from
heap allocates it would be suprising.
WH: How does stack allocation work if the reference to the allocated object escapes the scope?
WH: Important to be able to mark StructTypes to always generate opaque fat pointers even if they don't have any 'any' field.
WH: This helps with optimization. Knowing that all instances of a StructType are opaque lets NaN-boxing implementations optimize out protection against NaN-injection on reads.
Value Objects
Jan 30 Meeting Notes
John Neumann (JN), Allen Wirfs-Brock (AWB), Yehuda Katz (YK), Eric Ferraiuolo (EF), Erik Arvidsson (EA), Rick Hudson (RH), Matt Sweeney (MS), Dmitry Soshnikov (DS), Sebastian Markbage (SM), Ben Newman (BN), Jeff Morrison (JM), Reid Burke (RB), Waldemar Horwat (WH), Doug Crockford (DC), Mark Miller (MM), Brian Terlson (BT), Luke Hoban (LH), Andreas Rossberg (ARB), Istvan Sebestyen (IS), Niko Matsakis (NM), Brendan Eich (BE), Rick Waldron (RW), Sam Tobin-Hochstadt (STH), Rafael Weinstein (RWS), Dmitry Lomov (DL), Niko Matsakis (NM), Simon Kaegi (SK)
Parallel JavaScript
RH: API is stable
RH: Parallel array data type is no longer there. Instead as methods on arrays and typed objects.
NM: To be clear you can have an array with structs in it.
RH: The sweet spot is games and image processing.
RH: No current show stoppers on implementation. Some things to work out related to GC. The strategy going forward. Be complimentary to the typed object spec. Will track it and spec parts of it Typed Object spec. "Close follower". Will move in tandem.
LH: To move to phase 1 we need to see some examples.
YK: Agree, we need to see where we're at.
AWB: Agree, we should have presentations to move from phase 0 to phase 1.
RH: I have presented twice already...
YK: Moving to phase 1 should require a presentation.
YK: Concerned that we are exploding the API with mapPar, filterPar, fooPar etc.
YK: Prefer static functions
EA: Or a standard module import {map} from '@parallel'
YK: this
in functions?
arr.map(obj.method, obj)
DH: The signature should just match the existing functions.
RH: Not less surprising. Just as surprising.
parallelModule.map(arr, func, ...)
// [T] -> .... -> [T] // same return type
NM: What would you call from
?
WH: It's too confusing to require completely different static function style for invoking parallel maps as compared to non-parallel maps. mapPar etc. method style is better than the proposed alternatives.
DH: It is always nicer to write a method call than a function call.
DH: Don't want a "bring me a rock" exercise.
EA: File issues on GitHub on the drafts (that are also hosted on GitHub).
MM: Worked well for Promises.
YK/MN to talk through the concern about a "ton of methods".
Conclusion/resolution
- Move Parallel JavaScript to phase 1
- Talk offline about design issues further
Structured Clone
DL: Is implemented in all browsers. Part of HTML spec. Hixie speced it. Hixie is happy with TC39 moving this to ES.
YK: Like to object to this motion. It is currently a giant set of scenario hacks.
DL: We want to add language objects that we want to transfer.
AWB: Cloning framework in ES.
DH: Is it possible to reform or do we have to start from scratch? Seems hard to reform. Too many issues.
MM: Fears that if we do not take it over and introduce something new. The old will continue to exist. We need a path to replace the existing system, including what PostMessage does.
DH: We need a roadmap. How do we handle transferables?
DH: Hixie (or Anne) added Map and Set to structured clone to HTML spec.
DL: We cannot add extensibility mechanisms if we do not own the spec.
YK: We should own the spec. Opposed to DOM specific extensibility methods. General extensibility mechanism are important.
BE: How would symbols work?
AWB: We have a symbol registry. As long as both side cooperate. Serialize to a registration key. The two sides need to agree.
MM: It is unobservable that the symbol is not the same across the two workers.
WH: What if you have the same symbol registered under two different strings?
MM: That can't be allowed.
BE: in the cross-machine limit, structured clone is serlialization/deserialization; start there, allow optimizations like Sun XDR, Van Jacobsen TCP/IP, Google protocolbuffers [discussion on optimization]
WH: What do we mean by optimization?
DH: [explains difference between opaque and structured clone, including implications on optimization]
WH: Are we going to settle on one of the two or do both?
DH: Both [more discussion on optimization]
BE: [explains history of prior work]
BE: Can't tell Hixie and Anne to stop adding to structured clone. Anne: Want to give them assurance that we will take over the effort.
WH: What's the consensus?
YK: We'll take it on. Move to stage 0.x
defineGetter, defineSetter etc in Annex B?
BT: IE ships this.
MM: It would just be speced using defineProperty etc
AWB: Firefox does some strange things.
BE: please enumerate "strange things", file bugs
YK: It starts at level 1. Or 3? there are already implementations.
RW: What sites?
BT: Will attempt to furnish a list of sites...
Conclusion/resolution:
- Makes sense to put in ES7 annex B
- Brian to write an initial speec draft
Process document
Process doc is now publichttps://docs.google.com/a/chromium.org/document/d/1QbEE0BsO4lvl7NFTn5WXWeiEIBfaVUF7Dk0hpPpPDzU
Scheduling for next meeting
April 8-10 at Mozilla, San Francisco May 20-22 at Facebook, Menlo Park July 29-32 at Microsoft, Redmond Sept 23-25 at Bocoup, Boston Nov 18-20 at PayPal, San Jose
Async/await
LH: lukehoban/ecmascript-asyncawait
LH, MM: await syntax is important because the precedence of await needs to be different than yield.
LH: async functions could be combined with function*; in such a thing we'd need both yield and await
MM, WH: What would the behavior of such a thing be?
LH: That's a seperate proposal - something we can discuss later.
BE: Syntax conflict with => functions (elided parameters). what does: async() // newline, no semi here => {...} ...
mean? We can make it be an async arrow if we want, but second line looks like 0-param arrow function expression....
WH: async (a, b, c) => await d looks too much like a function call of
a function named 'async'. Need to parse a long way before figuring out it's an async lambda. This wouldn't fall under the existing cover grammar.
LH: I'll look into that.
DH: Initially concerned about hard-coding the scheduler.
LH: Identical to Q.async. There is only one way to do this.
MM: September Promises consensus is superior to the Promises spec we have now. [Debate about whether we'll end up with two Promises APIs]
WH: Do the two APIs use the same scheduler (that would be hardcoded)?
DH: No.
LH: Can we move async/await to stage 1? General agreement
AWB: This means that we agree that this is something in a future version of ES
Conclusion/Resolution
- Moved async/await to stage 1.
- Next step is to write real spec language
Promises discussion
MM: Advocacy for .then()/.cast()
STH: Advocacy for .chain()
LH: Proposal of Promise.chain() compromise
YK: I would probably be ok with this
MM: I would probably be ok with this ... extensive discussion ...
MM: A resolve of a resolve does not create multiple levels of wrapping. Without chain this is not observable.
BE: .chain() requires over-wrapping/-unwrapping, without chain this is unobservable and therefore optimizable -- says to reject chain (surprised by own position changing)
YK: This persuades me that we shouldn't have .chain()
STH: I strongly disagree, but I'm not going to hold up ES6 over this
Conclusion/Resolution
- Promise.cast is renamed to Promise.resolve (remove old Promise.resolve)
- Keep then, reject chain (NOT DEFER, reject!)
- Renaming .cast thus removes over-wrapping (always-wrap) deoptimization in old Promise.resolve
Some further discussion on keeping the spec inheritance/AOP-friendly by not using .then internally some times, short-cutting through internal methods or internal helpers other times YK, MM, AWB have details
January 27 2015 Meeting Notes
Brian Terlson (BT), Jonathan Turner (JT), Jordan Harband (JHD), Allen Wirfs-Brock (AWB), John Neumann (JN), Rick Waldron (RW), Eric Ferraiuolo (EF), Jeff Morrison (JM), Sebastian Markbage (SM), Erik Arvidsson (EA), Peter Jensen (PJ), Yehuda Katz (YK), Dave Herman (DH), Waldemar Horwat (WH), Alan Schmitt (AS), Michael Ficarra (MF), Lee Byron (LB), Dmitry Lomov (DL), Arnaud Le Hors (ALH), Chip Morningstar (CM), Caridy Patino (CP), Domenic Denicola (DD), Mark Miller (MM), Kevin Smith (KS), Andreas Rossberg (ARB), Istvan Sebastian (IS), Sam Tobin-Hochstadt (STH), Brendan Eich (BE), Jafar Hussain (JH)
Introductions
JN: No changes to agenda? We can change the order as we go
JN: Any objections?
JN: No objections
JN: Previous meeting minutes?
Conclusion/Resolution
- Approval of agenda
- Approval of minutes
4.1 ES6 End-game schedule review
(Allen Wirfs-Brock)
(include link to slides)
AWB: June, Ecma GA meeting:
- Approve standards
- Meet twice a year, next in Dec
AWB: We want ES6 to approved in June this year. What does it take to achieve that?
AWB: Final editorial works needs to be done. Takes a couple of months. Needs to start April 1st.
AWB: Before that TC39 needs to approve the ES6 spec. March 24-26 meeting...
Content is in slides…
IS: Question about different dates and document versions. His problem was that the documents for opt out are not the final documents that go to the GA for approval.
AWB: Will get to it on the next slide
AWB: Everything I say here also applies to ECMA 402 (the i18n spec). Rick Waldron is responsible for that and it needs to follow the same milestones.
RW: This will not be a problem for 402
IS: The opt out period needs to be over before June 17 latest, because that is the day of the Ecma GA, when Edition 6 is up for approval. This means that theoretically we may start the opt-out on April 17 the latest. In practice of course that is too late, we should find an earlier opt-out starting date.
IS: Anticipate large changes?
AWB: No, I hope not.
DH: Had some module related issues but did not want to bother Allen since he was busy related to subclassing issues. If we don't resolve these issues then we will not be done.
AWB: Does anyone expect to have issues that will cause the spec to slip?
DH: There are issues that need to be addressed, regardless of consequence.
AWB: Need to resolve those issues at this meeting. These dates are really hard deadlines.
DH: Can try to assemble a list of these issues this week.
IS: Is the opt out going to be on revision 31 or the final spec?
AWB: Can we do that with the final? Can we start the opt out on April 1st?
IS: Why don't we start the opt out on Feb 20, and use whatever spec draft we have then?
RW: Why can't the opt out start on Apr 1st.
IS: Would also work. But earlier is better.
RW: Gived more time to wrap up more issues.
AWB: It does not really change much.
AWB: 2 things going on: 1) TC39 approving the spec.
AWB: Feb 20 gives us (TC39) 30 days before the f2f meeting to review the last spec. Feb 20 is the day!
AWB: We don't need multiple opt outs. So the opt out period can start on Feb 20th (instead of Feb 1st as in the presentation).
4.3 ES6 draft status report
(Allen Wirfs-Brock)
(Same slides as previous item)
AWB: Three drops since last meeting, changes in the slides as well as harmony:specification_drafts
AWB: The HTML comment extensions in B.1.3 need to be reviewed against what browsers actually do.
WH: I'm validating grammar from main body of the standard (and found some minor bugs), but not going to validate browser extensions.
DD: I will try to do that, maybe.
EA: If we add the module tag (script[type=module]) do we need to keep this open?
DH: We can always remove the forbidding phrase if we see a need for it.
MM: Want to forbid in strict mode...
AWB: Not possible.
MM: Ok.
JHD: Browsers (IE vs Safari vs Chrome/Firefox) do different things in to HTML comments. In fact, even a single browser does different things depending on where the source code is coming from (script block, eval, console, ...)
MM: if you don't require [HTML comments] or forbid it, it's optional, [which makes it hard to fix in modules later]
WH: I'm objecting to have different behavior for browser ECMAScript vs non browser ECMAScript.
DH: The following program is valid when HTML comments are not supported
x
<!--y-->
z
MM: This is enough to show that there is an XSS issue. If the defender assumes HTML comments works or not.
WH: You can't go down the combinatorial explosion of different browsers' or different contexts' parses. The only sane thing is to reject this of you are writing a validator.
MM: Waldemar do you agree with if we cannot prohibit it everywhere we have to allow it everywhere?
WH: No.
MM: Would it be more predictable if it were allowed everywhere?
WH: Not in practice because existing browsers differ in parsing the extensions. Regardless of what we enact for ES6, for security purposes you have to handle the browser diversity anyway.
MM: I give up.
YK: You can use CSP to prevent eval.
MM: I think the current spec is fine. It is no worse thatn the current situation.
AWB: We need some eyes on this grammar.
Conclusion/resoltuoin
- Use the new annex spec for html comments as in the latest draft
- Need to review the grammar
AWB:
let x = expr
gets to x
, captures that identifier, then evaluates expr
.
ARB: Not clear when this is observable?
DH:
obj = {x: 'here'};
with (obj) {
x = (delete obj.x, 42);
// {x} = (delete obj.x, {x: 42});
}
AWB: New document title
YK: I recalled that we talked about not changing the name until we announced the new train model.
(still during the break) discussion between MM and YK: about Window/WindowProxy issue, discussing concerns, esp as relates to jQuery. MM: preferred to keep invariants, add test262 tests, wait for browsers to fix YK: points out Object.prototype.toString.call(window) results differ (Chrome: 'global', Safari: 'window', eg) … more discussion about configurability, differences between Window and a WindowProxy …
4.4 Subclass instantiation reformation: status and open issues
(Allen Wirfs-Brock)
The presentation continues
AWB: Walks through consensus from Jan 7 ad-hoc meeting (see slides)
YK: We should opt on the side of future proofing and fewer features.
WH: Is there any cases where these uniitiallized objects can escape?
AWB: Only if the constructor calls out before it is done with the initialization.
AWB: Not having to worry about reentrancy or uninitialized objects leaking allowed AWB to eliminate 20-25 pages of spec.
WH: Where exactly does a constructor's [[Prototype]] point in the no-extends, extends null, and extends non-null cases?
AWB:
- extends non-null: the superclass
- extends null: Function.prototype
- No extends: Function.prototype
WH: If someone mutates prototypes, the code uses the new superclass in some cases and the old one in other cases. In particular, the extends-null case uses the old one, while replacing a non-null case with another non-null case uses the new one.
AWB: Have ideas on fixing that.
YK: Can we make returning anything but undefined or an Object throw an exception?
AWB: Then we would have different sementics between class constructors an FunctionDeclarations/FunctionExpression
WH: Why are the exceptions in points 8 and 9 of AWB's slides different? That seems weird. 8. When a function implicitly returns from a [[Construct]] invocation, if its this binding is still uninitialized a ReferenceError is thrown. 9. When a function explicitly returns a non-object from a [[Construct]] invocation and its this binding is still uninitialized, a TypeError is thrown.
YK, MM, WH: Thought there was agreement on the list to make class constructors non-callable.
ARB: What about arrow functions?
AWB: super (like this) needs to work inside arrow functions. And it needs to work as if the super call was done outside the arrow function. This more or less means that the lookup of NewTarget, HomeObject etc is looked up in the outer scope of the arrow function.
WH: What if super is reentrant? Stashing it away via arrow functions allows code to reenter it.
ARB: Surprised and concerned about this as well. Implications unclear when super() is allowed to leak from constructor through an arrow function.
AWB: You can call super twice but you will get an exception when you try to bind this after the second call.
ARB: Possible implementation concerns?
DL: Should work fine.
WH: Wondering about calling super twice and having it throw only after the second call completes and tries to assign to this. Not sure about all the implications yet, but ok with it — the alternatives are worse.
MM: TCP for super.foo
is clear bt what about super()
in a constructor?
AWB: Both works in the latest draft.
WH: What is the NewTarget in the case of new super()
?
AWB: The NewTarget is whatever was part of the new func
so in this case
funct
. The NewTarget gets forwarded down.
WH: OK, so if you have a chain of [[construct]] calls, it's the base of the chain. What happens when new super() gets called from a function invoked via [[call]] instead of [[construct]]?
AWB: Error. Have to verify how it is specced.
DL: We could also use the function itself.
AWB: That is an option. [Checking spec.] -- throws a refernce error if there is no NewTarget which is the case when the function was [[Call]ed and not [[Constructed]].
AWB: My suggestion is to keep new super()
.
YK: Wants to dissallow all forms of super outside of class bodies
AWB: The primary utility is that you can use it in cases where super()
does not work.
DL: You cannot use new super()
in method.
YK: Wants to do a max-min approach here.
DL: are there critical use cases for new super() in constructors? I guess no
AWB: confirms
BT: how concern are you about removing new super
?
AWB: Should not be too bad. Pretty self contained.
BT: Anyone defending new Super()? crickets
AWB: Next, do we need syntax to manifest NewTarget?
YK: Early strawman was arguments.constructor
.
MM: <keyword>.prop gives us new
AWB: Sees options in the future to add things like function.callee
AWB: Maybe it could be class.target
but new.target
is more accurate.
These are called MetaProperties in the spec.
MM: Thinks that we should include new.target
. Understands the objections
but it is a very useful thing to have and it reads very well.
MM: Anyone object to have new.target
in ES6?
YK: Wants to talk about callable constructors before we make a call [no pun intended].
YK: OK with new.target
if constructors are not callabele.
AWB: Where is super()
allowed? Currently only allowed in class
constructor bodies.
ARB: Makes sense at this point. We have had multiple threads about this?
DD: Would new.target
work in FunctionDeclaration/FunctionExpression?
AWB: Shoudl work.
YK: Objects. We should opnly allow new.target
in places where super is
allowed.
AWB: new.target
can be used anywhere where [[Construct]] is used
DL: new.target
gets set/bound when [[Construct]] is done. This is valid
for normal functions as well constructors
ARB: There is no design issues here. It can only mean one thing.
EA: new.target
is tied to [[Construct]], not super.
YK: OK.
WH: What happens if you do ES3 style constructor/prototype?
AWB: The NewTarget gets set as you do [[Construct]]
EA: You can pass along NewTarget if you use Reflect.construct
YK: A possible semantics for new.target on [[Call]] is to throw.
MM: represents YK's point. If class constructors are not constructable and we disallow new.target in function declarations, then we don't have to answer the question of what happens with new.target on [[Call]]
AWB: ???
DD: Do we want people to refactor functions to classes. Then supporting [[Call]] and [[Construct]] is important.
AWB: Not sure if we are going to resolve these things quickly post ES6?
YK: No chance of getting concensus for ES6.
DD: If someone writes a FunctionDeclaration and wants to enforce that it is
called with new, then if we don't have new.target
people will go back to
instanceof and other broken heuristics.
DL: You could also use new.target usefully in a [[Call]] context - to assert that it is not a [[Construct]] context
BE: We don't know what the future holds but we do know that functions in
the past have been callable and constructable. What we do know is that
new.target
is useful.
WH: If we're going to use new.target === undefined to distinguish [[Call]] from [[Construct]] contexts: Is is possible for new.target to be undefined inside a [[Construct]] context? Even if it's called via reflection?
AWB: No, that's never possible.
MM: Reflect.construct(??, null) is a type error?
AWB: Yes, it is a TypeError
AWB: null or undefined
MM: undefined is least surprising.
EA: Because missing is often signalled with undefined.
BE: Strict functions uses undefined for missing this.
BT: Is new.target
undefined in global scope.
AWB: It is SyntaxError in global scope, just like super and return.
MM: Is it a syntax error in concise methods? They do not have a construct.
AWB: That would include more exceptions and reduce consistency.
MM: new.target
is also tcp through arrow functions.
Conclusion/resolution
- Remove
new super()
new.target
is available in all functions. It isundefined
in a non [[Construct]] call.new.target
in arrow functions gets the NewTarget of the outer context (not the arrow funciton context).
super() outside class constructor body
(Champion???)
DH: ????
YK: A constructor is both callable and constructable. If you use super()
in call context you do not know if it is a call or construct.
BE: super-dot is orhtogonal to super-call
MM: Do we have concensus on super() is only allowed in constructor? And constructors are only [[Construct]]able, i.e. their [[Call]] trap throws?
MM: Would like to postpone toMethod post ES6?
YK: Current design is insufficient.
DD: What about if someone wants to use super in functions'
YK: They should just use classes.
BE: Deferring toMethod and making a call on a class throw seems like the most future proofing.
WH: Can you explain what toMethod is?
AWB: Explains the spec
YK: Concerned about having toMethod(homeObject)
and then change the arity
to toMethod(homeObject, propertyName)
.
AWB: Just reserve the second argument.
DL: As a user, what do I pass?
WH: Also wants to defer toMethod.
AWB: Wants one more go and then I'll give up
AWB: People that wants to do meta programming. Polyfills, compilers. All of these people are now shut out.
DD: Without toMethod you cannot add a method that wants to call super to an existing class. E.g. for a polyfill on a DOM class; especially custom element callbacks.
MM: When we started we set out with a design that could explain classes using ES5 semantics. We've lost this with TDZ.
DD: Feels strongly that classes should desugar to smaller primitives. Since we have already lost that we can/should come up with a more consistent design post es6.
DH: We have to go from both ends. We are not abandoning, just deferring.
BE: We want kernel semantics. But we should not rush this. We will regret rushed decisions. We do not have solid design at this time so we must defer.
DL: No super()
outside class constructors since this is already
initialized.
AWB: My bottom line; new.target
and super.property
are the essential
things.
DL: extends null?
AWB: We can drop the special dynamic case for extends null. Can have the constructor return an object it makes itself via Object.create.
EA: If you have an extends clause, the default constructor calls super. If the extends expression evaluates to null then the super() call will throw. So you have to provide your own constructor
class Foo extends null {
constructor() {
return Object.create(new.target.prototype);
}
}
AWB: If not null then the extends expression must be IsConstructable.
DL: What is the canonical way to create a class that has null as the [[Prototype]] of the instance
MM:
class C {
constructor() {
return Object.create(new.target.prototype);
}
}
C.prototype.__proto__ = null;
WH: We special case the null value in the extends clause. If null we use %FunctionPrototype% as the superParent. We use null as the protoParent. Get rid of the specialized treatment of super() for null extends; instead, use the same semantics for null and non-null extends, which will make any attempt to call super() with a null extends throw.
class C extends null {
constructor() {
return Object.create(new.target.prototype);
}
}
AWB: super.property
in object literals works in concise methods and
accessors.
AWB: Do we have concensus to remove super.property
from concise methods
in object literals.
YK: I think that is unfair. We have made a lot of changes.
DL: Concise methods are not constructable. Correct?
AWB: Correct.
DD: We cannot reopen unrelated issues at this time of the process.
YK: I'm passionate about the syntactic sugar related to super()
for
super.propertyName()
. This syntax got removed and we had to do some
fairly significant changes. And this is related.
WH: Was under the impression that super.property
was only going to be
available inside class methods.
AWB: There is no distinction between class methods and object methods.
MM: When we talked about this before I was also under the assumption that this was about inside classes and outside classes.
Conclusion/resolution
- Dropping toMethod from ES6.
- No
super.property
in FunctionExpression/FunctionDeclaration (as well as generators). - No
super()
outside class constructors. - Class constructor [[Call]] always throws.
extends null
does not have special dynamic default constructor. The syntactic presence of extends clause causes [[ConstructorKind]] to be derived.- No concensus on super inside concise methods of object literals. (to be revisited)
Methods in class bodies enumerability?
AWB: Is anyone objecting to making methods in class literals non enumerable?
No objections.
Conclusion/resolution
- Methods in class bodies are non enumerable.
- Concise methods in object literals are still enumerable.
January 28 2015 Meeting Notes
Brian Terlson (BT), Jonathan Turner (JT), Allen Wirfs-Brock (AWB), John Neumann (JN), Rick Waldron (RW), Jeff Morrison (JM), Erik Arvidsson (EA), Peter Jensen (PJ), Yehuda Katz (YK), Dave Herman (DH), Waldemar Horwat (WH), Dmitry Lomov (DL), Domenic Denicola (DD), Kevin Smith (KS), Andreas Rossberg (ARB), Istvan Sebastian (IS), Sam Tobin-Hochstadt (STH), Michael Ficarra (MF), Jordan Harband (JHD), Chip Morningstar (CM), Mark Miller (MM), Ben Newman (BN), Brendan Eich (BE), Adam Klein (AK), Igor Minar (IM), Misko Hevery (MH)
Report from the Ecma Secretariat
(Istvan Sebastian)
IS: Strange JSON development: The government of the Netherlands wants to get an EU recognition on IETF's JSON future standard as part of the European Commission's Multi-Stakeholder Platform. Netherlands submitted 27 IETF standards to the Multi-Stakeholder Platform, and IETF's JSON happens to be among them. Normally only long-standing in the market already proved standards should be recognized. Also no "consortium specification" should be recognized where appropriate International Standard (like of ISO, IEC, ITU) exists. JSON in ECMA-262 is already part of ISO/IEC 16262:2011. In addition TC39 has standardized in 2013 ECMA-404 (JSON). We had originally a TC39 decision to fast-track it to JTC1, but after discussion the GA in December 2013 has approved the possibility of a Postal Balot on the JTC1 fast track upon a new request from TC39. The iisue has been reported to the last Ecma GA and was worried about the situation.
WH and IS: [Discussion about what the Multi-Stakeholder Platform is and its implication on governmental activities]
IS: Recommend resuming the fast-track of ECMA-404 (JSON).
AWB: We don't currently have an editor for the JSON spec. Who wants to do it?
CM: I volunteer!
WH: Timeline? June GA?
IS: Will discuss it with ECMA management. Might do it earlier via a letter ballot.
ES6: Generator issues
(Allen Wirfs-Brock)
WH, DH: Ask for presentation.
AWB:
DH: Earlier presentation was careful to allow try/finally to abort the return. The point was to allow infinite iterators that refuses to return.
BN: Filed this bug. You could change the return method to return {done: true}
.
DH: You can have wrappers that are specific for for-of loops.
AWB: THe original proposal required a falsy done value. If it wasn't falsy an error was thrown.
DH: You could change the for-of loop by wrapping the iterable to not continue the iteration of the underlying
var nats = getNats();
for(x of nobreak(nats)) {
if(cond) break;
...
for(x of nobreak(nats)) {
if(cond) break;
}
}
function nobreak(it) {
return {
next(x) { return it.next(x); },
throw(x) { return it.throw(x); },
return(x) { return {done: true}; }
};
}
YK: If someone asks to cleanup, by calling return, then you should clean up.
KS: There should be an equivalent of an iterator with a return and without a return. (?)
DL: having a nobreak is an abstraction breakage ; you have to know whether your iterator is infinite or not, or rather, has something useful to do in return
WH: Why is return(x) stubbed out but not throw(x) in DH's nobreak?
WH: What happens when there is a throw inside the for-of loop body. Does it call "throw" or "return"?
AWB: (looks up semantics)
BE: If there is a throw in the for-of, the "return" method is called, not the "throw" method.
DH:
var nats = getNats();
nats.return = () => ({done: true});
for(x of nobreak(nats)) {
if(cond) break;
...
for(x of nobreak(nats)) {
if(cond) break;
}
}
function nobreak(it) {
return {
next(x) { return it.next(x); },
throw(x) { return it.throw(x); },
return(x) { return {done: true}; }
};
}
AWB: Why can't we make that an iterator that says that it is done, that it
can never return {done: false}
again?
DH: Are you sayng that the default behavior should be {done: false}
?
AWB: Or that there is no default.
DH: There has to be a default behavior.
AWB: If there is not return method then nothing is called.
DL: As far as I understand, the intent was to close the iterator for for-of loops.
JT: The iterator consumer should not need to know if the iterator is infinite or not.
AWB: We cannot enforce that {done: true}
does not change to {done: false}
in the future.
DL: The contract of an iterator is that once it is closed you cannot get any more values out of the iterator.
AWB: You cannot enforce that. It is up to the implementer of that abstraction.
DL: Normally, you create a new iterator every time (in for-of)
DL: Why is tehre a difference between finite and infinite iterators?
DH: What Jafar brought to the table was that infinite iterators are not the common case. The common case is finite, like file streams etc. You want these to close by default. We should not optimize for inifinite sequences.
DL: If you don't want to close then you should not use for-of.
DH: That is also Jafar's view.
AWB: Generators work this way. They do the right things.
YK: Was persuaded by {done: true}
meaning that I accepted your hand shake.
AWB: Say that this is just a hand shake is a completely different thing than what we have.
DH: Pretty persuaded that we do not have to catch this bug.
DL: You could throw in the return method.
DH: If you have an infinite sequence that you don't want to be able to close, throwing in return would signal that the user is using it wrong.
BN: If we adopt the policy that {done: false} would throw, it is not very different from than throwing in return.
EA: Using throw in your return is also a clearer intent.
WH: How would AWB's original motivational example (of a reusable infinite iterator) be done?
AWB/BN: The user would have to wrap the iterator and/or use try/catch
BN: Do we need to consider generators and try/finally and make sure we are not missing an opportunity to prevent bugs?
BN: no compelling argument to throw for iterators that do not have a return method, since they can just implement .return() to throw if they really want that behavior.
Conclusion/resolution
- Remove the truthy check for Get(result, "done") that follows the call of "return". (The value continues to have to be an Object.)
- Relevant bug closed with the following comment: ecmascript#3395#c2
4.5 @@toStringTag
(Jordan Harband)
MM: Do we check the natives before checking the symbol?
AWB: Step 17b, for natives we get both and then if the tag is different a tilde is added.
JHD: We could make all builtin instances have own non configurable property
MM: Or skip the override for the built ins.
JHD: Not looking for complete security. Just want to error if the user does crazy things.
MM: In es6 classes, if you extend a RegExp the instance is going to continue to be a regexp instance.
JHD: One use case is for a module that wants new Boolean(false)
to be
same as false
. Not saying that is a good library, just explaining how it
works. With ES6 and someone overrides @@toStringTag these tests no longer
work.
YK: If someone sets the toStringTag to Boolean they probably did that because they want to go down the Boolean code path.
DD: If you want to do it the right way there are other ways. Allen posted this to es-discuss. esdiscuss.org/topic/tostringtag-spoofing-for-null-and-undefined#content-59
KS: There are builtin methods that throw if the internal slot is not present.
WH: AWB's brand checks are optimized for the true case. That's ok for error checking (I expect x to be primitive Foo and don't care how slow the code is if it's not) but not good if you just want to reliably test if x is primitive Foo.
DD: Believes that there is a method that does brand checking for all the builtins.
MM: Checked Caja for brand checks. Found 5 cases. Not clear if they would be safe with alternative brand checks. I'm convinced that Allens proposal is safe enough.
AWB: Then we can step 17 (the tilde case).
MM: Just to be clear, there is no way to change what typeof returns.
MM: Issue is ES5 libraries coexisting with ES6 clients.
JHD: What if someone claims that a String is an Array.
YK: Then they get an error which is what you would expect.
MM: Requests that browser makers wait for at least 2 months before releasing a browser that drops step 17. The integrity of Caja is at stake.
[agreed to MM's request]
Resolution/conclusion
- Remove step 17b in the alg (the tilde prefix requirement). 19.1.3.6 Object.prototype.toString ( )
- Agreed to wait 2 months before releasing a browser that does this
Super revisited
YK: Happy with the outcome.
Conclusion/resolution
super.property
is available in all concise methods (including accessors) in object literals.
Experimental new directions for JavaScript at Google
(Andreas Rossberg)
[Slides: www.mpi-sws.org/~rossberg/papers/JSExperimentalDirections.pdf]
ARB presenting
AWB: [On methods doing instance brand checking.] Why cant you make the methods non extractable instead?
ARB: Then you probably need [[Invoke]] which is problematic too.
WH: What about calling a funciton with too many arguments?
ARB: We discussed this. People want it for API evolution. Allowing it makes sense with subtyping.
DH: Does this mean that V8 would be slower for non sane js?
ARB: Of course not.
PJ: How is this going to make the VM code simpler.
ARB: It doesn't, but it might avoid making it yet more complicated in the future.
WM: The goal is to make performance more predictable.
WH: Trying to probe the interaction of sane and non-sane modes. I assume that the sane mode will have strings and a string generated in non-sane mode code will be usable in sane code and behave and be typed as a string.
ARB: Yes.
WH: Then what happens if in sane mode I take strings s and t and call s.concat(t). Does sane mode statically determine that the result is a string (which would cause issues if String.prototype.concat is monkey-patched), or does it do the conservative thing and assume that the result of the concat call is any, in which case I can't assign it to a string variable.
ARB: Use any<string>
DH: Better-is-better vs. worse-is-better
DD: I see this as an alternative to asm.js but writable by people.
DH: I see building on asm.js as an alternative way.
ARB: We are talking to the asm.js team. Both valuable, goals are mostly orthogonal. user-facing vs compiler target.
DH: Believe we can add parts of this in one js.
WH: [In response to OneJS assertion that we should wait for us to make the entire language more optimizable instead of making high-efficiency subsets.] We've been going in the opposite direction. We are making things harder to implement and reason about in ES6. For example Proxies.
DH: would prefer implementors' time be spent optimising existing JS instead of optimising this subset
AR: False dichotomy: subsetting means that it is existing JS.
BE: Think that it might be hard to pull this off but it might be informative for future JS features.
STH: You cannot go from an unsound type system to the system you have in your vm.
BE:
STH: Unsound type systems are not usable for performance. If we want types to help the VM it is not going to happen as an evolutionary type system on top of TypeScript or Flow.
BE: Concerned that it is taking resources away from other more important things.
JT: Even unsound types can be used as hints to the VM.
ARB: Yes, but not much more. You only save a warm-up cycle compared to the current state of affairs. The real perf issues we see is when the type assumptions we make are wrong and we get into deopt/opt cycles. It is very hard to reason about when this happens and it does happens when your application gets larger. Also, more aggressive optimisations require global invariants, which you cannot achieve without globally sound types.
YK: As engines gets smarter the risk of hitting the pathological cases is getting worse.
YK: We hope the engines are not changing their heuristics because we are currently targetting one heuristics.
ARB: Exactly. The smarter VMs get, the less predictable performace will be. Types are the only way out we know of.
YK: I hope that you are planning to write a transpiler.
ARB: Yes, we start prototyping in Traceur.
BE: Why was flow not consired?
ARB: Flow is going in the opposite direction. It is doing more inference. It is a non starter for doing inside a VM.
ARB: Typed racket great, but occurrence typing can potentially get expensive.
STH: That is not accurate. THere are ways that you can make things slow but there is no inherent reasons it needs to be slow.
BE: If you want adoption. Peopke will go the extra distance to get the predicable performance.
YK: Can imagine a world where a language significantly compatible with JS has usages.
JM: Flow would want to be compatible with whatever we develop.
ARB: It is complementary. Write in Flow style and have Flow insert type annotations for you.
BE: ... Java failed, ActionScript failed
STH: I would not say Java failed. People like static typed languages.
WH: If Java failed, then what succeeded? Objective C?
JM: There are several large JS code base projects and a lot of them came to the conclusion that static types helps them manage their code.
STH: The difference between Andreas' proposal is that there is a concrete plan for VM optimization.
BE: Afraid that this will be designed in some corner inside Google.
ARB: No. We just had a meeting between all parties interested in types for JS, presenting this. And we totally intend to continue those.
YK: It is important that interested parties are part of the designing this.
ARB: Someone has to make this experiment. We cannot spec a type system without a working implementation. We need to explore and validate options.
DH: Interop layer. How do these things interact? How smoothly can new and old code interop? In your part of the space you need soundness and you need to drop some of the constraints. It is not an end user target. It is either a target for compilers or for code where you really need to squeeze out maximum performance. What can you do in a type system and keep it smooth.
WH: This has different goals from asm.js. Asm.js does manual storage management instead of gc; this effort doesn't go that far.
ARB: We did talk to asm.js people to make a version of asm that would support gc etc.
STH: If someone had said 3 years ago that types would be the next big thing in js we would not have believed them. It happened (TypeScript etc)
BE: Try to make it a name that impies that it is natural progression to js. You should try to deemphasize the mode.
DD: Calling it "sane mode of Javascript" instead of "sanescript" would be much better.
BE: What about "use types"?
KS: It is not clear to me what the dependency is between the new mode and type?
ARB: Neither am I. :)
DH: What matters is how far you are diverging from the language.
ARB: Some traditional patterns you do not need any more with ES6. For example Maps makes usage of Objects as a map obsolete.
DH: You are better doing these things incrementally. One thing at a time. If one of these succeeds or fails it does not bring everything down or up.
WH: Little incremental steps cause too much complexity due to the constant arms race to fool existing code while introducing new features. Look at the evolution of ways of defining properties.
DH: We can all list flaws with JS.
WH: This proposal is one of the few that reduce entropy.
DH: Not true. It sits on top of the existing language.
YK: Makes the way the language feels very different.
DD: JS stays within the bounds. It is like a really strict linter. Don't think there are that big of a difference.
AWB: Great to do experiments. New mode. Substantial different language. Skeptical to get this rolled out in the short term.
ARB: One design goal is that a "correct" program that works in sane mode engine will work in all ES6 engines.
MM: Plausible route to success. Frozen classes can be adopted. Almost identical to const classes as previously proposed. Want to bring this up after ES6. For things that do not fit that model, the train wreck you are going towards is sharing primordials. You end up duplicating all the primordials. The realm api we are working on is an alternative way to approach this.
ARB: There is no intention to have to duplicate all the primordials.
MM: As you continue towards this goal you will continue to duplicate more and more primordial.
6.3 Decorators
(Yehuda Katz, Jonathan Turner)
jonathandturner/brainstorming/blob/master/syntax.md, jonathandturner/brainstorming/blob/master/README.md
JT: TypeScript wanted annotation/decorators. Talked to Yehuda and agreed to try to come up with a common proposal.
AWB: Is using @ going to cause grammar issues with using @ for private state.
EA: @ is widely used in other languages for annotations.
MM: would rather talk about semantics than focusing on the token.
YK: Want to resolve it now because wants to move forward. Wants to move to stage one
AWB: Does not matter. There is no commitment on the syntax for stage 1.
YK: We are reaching a point where people are using ES6 class syntax and run into issues where it is not expressive enough. They end up adding their own syntax.
WH: There seems to be an ambiguity with the syntax for Decorator.
@x instanceof (y) ...
WH: is instanceof the name part of a MethodDefinition or a continuation of the decorator expression? An ambiguity like this can also cause the lexer to go off the rails if you concoct a more complex counterexample with a / inside it and you wouldn't even be able to lex to the end of it to see what follows.
WH: One option to solve this is to limit decorators to primary or simple expressions. Binary operators cause issues. If you want a complex expression as a decorator, just parenthesize it.
YK: So we can solve by restricting the grammar
BT: Or using a delimiter like colon after the annotation
YK: Basic idea of decorators is that there are 2 things that can be decorated. Classes and class methods. Give the decorator a chance to intercept. They take the same params as defineProperty and can return the descriptor that is finally installed.
({
foo: observes(function() {
}, prop)
})
MM: It is really just a desugaring of wrapping the defineProperty calls.
MM: Do super work after the method has been decorated.
YK: There is one quirk with getters and setters. They are installing a single property descriptor but there are multiple instances in the syntax.
EA: We have issues with duplicates
AWB: We have tried to solve this in the past (to bind the get and set pieces together).
MM: The idea that you are decoratign a descriptor and not just the value is powerful.
DD: You could pass in a flag.
JT: Lets pop the context and get a good overview before we start diving into the details.
YK: Noted that there are quirks.
YK: @readonly is a simple example of decorators.
IM: Annotations doc goo.gl/42o100 (requires permissions) Decorators vs. Annotations: docs.google.com/document/d/1QchMCOhxsNVQz2zNvmzy8ibDMPT46MLf79X1QiDc_fU/edit# (requires permissions)
IM: What do we want annotations for? Collected use cases in document. For example for documentation, ORM, DI, tooling aspects
WH: What is the syntax for annotations?
YK: At this point it is the same as decorators.
IM: Biggest difference between deocrators and annotations is that annotations support static/ahead of time tooling because it has guarantees you can build on top of.
WH: Big issue is whether you use a separate sublanguage for static annotations or try to use the same language. Separate language using separate name scopes results in solutions and problems such as C's preprocessor. Using the same language causes severe time-of-evaluation issues, as seen in Lisp's eval-when or C++'s template and class-vs-constexpr gotchas [example: a C++11 class constexpr reference can't use static constexpr functions defined earlier in the same class]. The problem arises in doing compile-time scope lookup and variable resolution in scopes as dynamic as ECMAScripts's.
MM: Do you expect to be able to have identifier expressions in your annotations? Do you expect that to look up the value in the current scope?
EA: The original proposal used expressions. There has lately been talk about scaling this back to JSON so that there are no side effects.
MH: Using JSON only seems like it might not be suitable enough.
AWB: There is a middle ground here. Classes could expose an extensible meta-object protocol. Essentially dynamic extension points that you can hook in to. So as part of defining a new type of class definition you might add meta properties and other things. Might be quite dynamic but have a static representation in the source code.
MM: If JSON is almost expressible enough, with the exception of the scope issue, and if you add IdentifierExpression
IM: We might be happy with that.
IM: One other reason for having these side effect free annotations is the VM perspective. Decorators needs to be dynamically invoked.
DD: The performance impact would not be worse than calling the functions yourself.
DH: Meta programming is generally the case where you do not need to optimize for performance because you expect there to be some penalty.
MH: If you only have decorators and the common use case is annotations ????
DD: If you are in a static environment you can already treat decorators as a special form.
MH: The order of decorators matter. The order of annotations does not matter. Therefore it does not compose.
YK: No one is saying that you cannot prevent people from using decorators for anything other than attaching meta data.
MH: Looks like decorators can do anything but in practice they cannot do much without using global state.
YK: Disagree. They can use the object as the coordination point.
MH: Lets assume I'm creating a component.
YK: You can use a weak map.
MM: Can you clarify.
MH: I think it is a good property that you can bootstrap the same framework multiple times. The problem is that a decorator needs to register itself with some context.
YK: The decorator can add meta data. Then you call the register with the relevant context.
MH: Yes. But the extra power is problematic.
MH: Depends on when you are running the code. Would like to wait until the framework has enough context.
AWB: Maybe have two different proposals, both at stage 0. Then try to unify them before they can progress to stage 1.
MM: Having one mechanism that satisifes both needs is preferable to having two different mechanism.
MM: Maybe you can have a statically verified subset of decorators and if that restriction is fulfilled your tooling can treat it as an annotation. If not it falls back to a dynamic decorator.
IM: Sounds promising.
Conclusion/resolution
- None?
January 29 2015 Meeting Notes
Brian Terlson (BT), Jonathan Turner (JT), Allen Wirfs-Brock (AWB), John Neumann (JN), Jeff Morrison (JM), Erik Arvidsson (EA), Dave Herman (DH), Waldemar Horwat (WH), Domenic Denicola (DD), Kevin Smith (KS), Michael Ficarra (MF), Jordan Harband (JHD), Chip Morningstar (CM), Adam Klein (AK), Igor Minar (IM), Misko Hevery (MH), Istvan Sebastyan (IS), Rick Waldron (RW), Ben Newman (BN), Yehuda Katz (YK)
Not present?
Peter Jensen (PJ), Dmitry Lomov (DL), Sam Tobin-Hochstadt (STH), Mark Miller (MM), Brendan Eich (BE),
PLEASE UPDATE THE PARTICIPANTS LIST!
ES6 Introduction text
(Allen Wirfs-Brock)
[Ask for slides]
AWB: The spec has an introduction text. We need to write what ES6 is adding to the picture. Right now it is empty.
AWB: Asked for volunteers and no one has done that yet.
Possible new text
ECMAScript is now one of the world’s most widely used programming languages; it has been adopted not just by browsers but also for servers and embedded applications, and has become a compilation target for other languages. The 6th edition provides the most extensive set of enhancements to ECMAScript since the 1st edition.
It is now a comprehensive general purpose programming language.
Some of the major enhancements provided by the 6th edition include modules, class declarations, lexical block scoped declarations, iterators and generators, promises for asynchronous programming, destructuring patterns, and proper tail calls.
The ECMAScript library of built-ins has been expanded to support additional data abstractions including maps, sets, and arrays of binary numeric values as well as additional support for the Unicode supplemental characters in strings and regular expressions. The built-in library is now extensible via subclassing.
New uses and requirements for ECMAScript continue to emerge. The sixth edition provides the foundation for regular, incremental language and library enhancements.
List of contributors?
(Allen Wirfs-Brock)
AWB: In ES5 there is a list of people who contributed to the spec. For ES6 the list is really large and I'm afraid of leaving someone out. Suggests not having a list of contributors.
IS: Non normative. Non mandatory. ECMA leaves it entire to TC39 if they want to have a personal and/or organizational recognition of those who have significatntly contributed to the standard. This can be from case to case different. E.g. in ECMA-402 (ECMASCript Internationalization) all contributors and those who even commented were acknowledged, but of course that standard has a much more focused scope. So it is up to TC39. If there is a risk of forgetting someone who has significantly contributed to the work on ES6 maybe it is better to leave it out.
BT: Is anyone asking for this?
JM: Does anyone oppose to leave this out?
DD: It feels nice to get acknowledged, and we should consider doing it in the future. Especially for e.g. ES2016 when we're on GitHub and can just look at the contributors list. But it's just not feasible for ES2015.
AWB: Suggests not having the list of contributors.
BT: Seconded.
JN: Would it make sense to list the companies that contributed.
WH: That would be worse.
EA: Agreed.
IS: He noted that in the past in Ecma we even had a few cases when companies have been acknowledged, or persones (with their companies in bracket). Up to the TCs how they want to handle this, because this part goes into an informational part of standard anyway.
Conclusion/resolution
- ES6 will not have a list of contributors.
March meeting
(John Newman)
JN: Next meeting is in Paris. Today is the last chance to object.
WH: Objecting, but will not veto it.
Conclusion/resolution
- The Paris meeting has been confirmed
IS: note after the meeting: We have to take into account that like in the SF meeting there will be members who will want to attend remotely via conferencing facilities. Therefore the host should be prepared for that and should provide a well functioning remote conferencing facilities. In the SF TC39 meeting the video part and the remote audio participation worked well, but the audio from the conference room could only be understood if one person alone close to the mic spoke.
const in sloppy mode
(Brian Terlson)
BT: Found one site that depends on the legacy const semantics.
YK: One site?
BT: It is also a demo site.
BT: While it is true that a site might serve different code to IE and Chrome.
DH: Let me talk to Jason Orendorff (SpiderMonkey engineer) and see what he thinks.
AK: At the moment you cannot use let in sloppy mode.
BT: It is worrying that Google thinks that this is not web compatible and that it has not been brought up before.
BT: We could change the semantics and make const in sloppy mode scoped like vars.
AWB: I would be opposed to that. I'd rather drop it.
DH: Opera used to treat const exactly like var.
WH: What is the issue?
EA: In legacy Chrome and Firefox (sloppy mode) const has the same scoping rules as var.
AWB: If we run into a brick wall we can revise the spec in the future.
BT: Time is of the essence. The longer you hold out the higher the risk is that IE would fall back to the legacy behavior.
BT: IE11 shipped the correct ES6 semantics for over a year and only encountered one problem report.
BT: Want to see plan to turn on proper sloppy mode semantics from Chrome and Firefox within the next few months.
EA: We'll make a plan on how to get to standards compliant const in sloppy mode.
Conclusion/resolution
- Google and Mozilla will move towards a standards compliant const in sloppy mode.
Object.observe
(Erik Arvidsson)
(Presents slides) docs.google.com/presentation/d/1VHdL37sZSLBZuizzSfiiSd9zSy9zNYXiNEjDJeTjOSA/edit?usp=sharing
AWB: Is "types" the right word in "acceptTypes"? These are actions, not types.
EA: These correspond to the "type" field, but agree that, if we're adding types to the language, also using the term "type" in this way would be not so good.
Discussion of skipRecords: what should be passed to the observer callback in that case? undefined or null? (Domenic to file a bug)
YK: Advance to stage 3?
EA: Not just yet.
YK: I would decouple Array.observe
from Object.observe
YK: I would like to get more implementation feedback (which would help prioritize it in libraries), but don't necessarily think that should block Stage 3 forever.
EA: Still details to be worked out over scheduling of observer callbacks
DD: ECMAScript-wise, just creating a job and enqueuing it should be sufficient
YK: That doesn't seem like enough, because the callbacks still need to run at end-of-microtask
DH: This sounds like maybe a seperable work-item
DD: Not clear whose court this is in, between Web specs and ES
YK: It seems like a small, self-contained note somewhere explaining the interaction of ES Jobs and HTML/DOM event queues
DH: It sounds like a WebIDL thing
AWB: 2 things: 1) Relative ordering of observe notification jobs.
Arv: The ordering is well-defined.
AWB: 2) Any ordering dependencies between your spec and promises. In ES6, promises have a well-defined ordering but other job queues can interleave between promises. So if you expect to have a defined ordering between observe and promise then you probably need to use the same queue.
YK: Needs a user-facing API for managing job queues.
AWB: Yes, quite useful.
MM: Why is Array.observe a separate API? Shouldn't the default be to observe splices when arrays are Object.observed?
AWB: Then you have to define what the extensibility story for other types.
MM: Understood.
Discussion of decoupling Object.observe and Array.observe
MM: You wouldn't want to ship Object.observe without Array.observe, though having two waves of specs is a separate issue
Conclusions
- null is preferred over undefined, more explicitly representing an absence of records
- No stage 3
BT: I have no idea what is going on, for the record.
ecmarkup
(Brian Terlson)
AWB: what is the difference between ecmarkup and ecmarkdown?
BT: Ecmarkup is HTML markup, such as <emu-clause>, <emu-alg> etc
BT: Ecmarkdown is a markdown syntax for specifying algorithms steps. Ecmarkup uses ecmarkdown inside <emu-alg> and a few other elements.
BT: bterlson.github.io/ecmarkup
BT: abstract operations from external specifications may be referenced
EA: There currently is no way to write BNF. We should add that.
WH: I have built tools for validating grammars
BT: I believe Allen would like to continue using Word
DH: No, we want to get away from that
AWB: ISO requires the document to be submitted in Word
DH: Jason has a tool for converting some spec sources to Word
DH: it is important to me that we work in markdown on github for the next version of the spec
DH: we may be able to leverage academics that want to represent semantics of JS in a similar way to the spec
BT: html imports are used, so a document may be split up into pieces
Interfacing with the Loader Spec
(David Herman)
[Link to slides]
AWB: How do you get a module record from a different realm unless you are using imperative APIs?
DH: I expect this to be pretty nitty gritty code. It is not going to be common to get cross realm modules.
DH: The basic idea is that every loader belongs to a realm and that when it process modules it uses that realms policies.
AWB: Why can't the records have all the fields but the fields are not filled in yet?
DH: Some of these fields make no sense for reflective modules.
DH: Reflective/dynamic modules are always leaves. Makes things a
Second day meeting notes.
Revisited octal/binary constants. Waldemar: Note that we currenty allow both upper and lower cases for a, b, c, d, e, f in hex literals as well as e in exponents and x in hex literals. Breaking symmetry by forbidding upper case for b and o to avoid lookalikes would be "nanny language design". We can't forbid lookalikes anyway: { let y = 3; { let у = 7; return y; } } This is a valid ES6 strict function body that returns 3, of course. The second let defines a local variable named with a Cyrillic letter.
Decision: Allow upper case B and O to start binary or octal literals.
Complex discussion about what's feasible in static checking of references from modules. Discussed issues with integrating script code eval'd from cross-origin XHR requests and the (anti-)merits of using var to declare globals.
MarkM: Abandon static checking. Waldemar: MarkM's example from yesterday is an important use case: using a typeof check to see if a variable is defined and later in the same module conditionally dynamically defining it if it wasn't and, even further down in the module, using it. A static check would flag the uses and prevent the module from loading. Allen: This is a good use case for pragmas.
MarkM, Waldemar: Example of a successful strict transition: Nowadays the two of us don't even know non-strict Perl because it's too weird. We learned the cleaner strict version, always set the pragma, and stay within the strict version. Anything non-strict is considered to be broken until it can be upgraded to strict.
Philosophical discussion about modality, whether a "mode" should be called a "dialect", etc.
Summary of static checking pain points that need resolutions:
Allen: Do top-level let and const create properties of the global object? DaveH (channeling Andreas): No, but functions do. Sam: If they don't then the T-shirt Erik is currently wearing wouldn't work. Many agreed that we can't break the T-shirt. DaveH: What if there are duplicate top-level bindings? MarkM: Top-level let should behave as much as possible the same as concatenated scripts. Waldemar: What about read-eval-print loops? MarkM: Each eval inserts one more nested scope. Waldemar: What if someone does this:
This would leave foo returning 3. MarkM: That's the proper behavior. Anything else has problems. Waldemar: [incredulous] Allen: We shouldn't spec read-eval-print loops.
DaveH's summary of issues:
Sam: What about global scope polluters? let Object = 7; should be an error. But implementations have other sources of polluters (such as predefined implementation features or other HTML elements on the page) that can cause global clashes. Allen: Top-level declaration overriding is allowed if the existing property has the attributes writable:true and enumerable:true (and the new declaration stays enumerable). Configurable doesn't (sic) enter the decision. Allen: See ecmascript#78 DOMs now declare properties on the prototype of the Window object.
Internationalization report Discussion about a name (and domain name) for the internationalization test suite. 402 is the current next unused ECMA standard number. We probably shouldn't wait for two more ECMA standards to be published.... Mild consensus on putting the test suite in a subdirectory of test262. Discussion about whether to keep internationalization as a separate document or to merge it into ECMA-262. Current decision is to keep it separate for faster evolution of both standards and to avoid bureaucracy with ISO. Discussion about the choice of name for the global variable via which the internationalization API is accessed. Possibilities are Globalization and Intl. Need to look for web breakage these would cause. Everybody needs to review internationalization spec before the vote in March.
Debate over whether to use TypeError or RangeError for domain errors. DaveH: Use TypeError Allen, Waldemar: Use RangeError. Note that RangeError is used for more than just numeric intervals -- passing 3.5 to a function that expects an integer in [0, 2^32) throws a RangeError in ES5.1.
Test262 status report: No invalid test cases left. MarkM: Want some means to avoid having test262 penalize implementations that anticipate incompatible breaks that have been approved by the committee (possible example: completion reform in ES6). Allen: Distinguish between spec bugs and breaking spec revisions. DaveH, Sam: In reality the test suite provides political pressure. Want to avoid applying that pressure for features that we decided to break in the future spec. Alex: Create a category of deprecated tests that, just like the nonnormative ones, run but don't factor into the score. DavidF (in response to discussion assertions about test262 always tracking only the latest ECMAScript version): Microsoft wants to retain an ES5.1 variant of test262 even after ES6 is released. Consensus: Create a third category of tests for features that are "no longer endorsed".
Mozilla hasn't signed a contributor agreement yet. Waiting for having something to contribute.
Istvan's report about the chaos that Intel caused at the last GA meeting and the developments since then. Allen: We should formalize the RANDZ for TC39. Intel will be here for the next meeting of TC39. TC45 also had an understanding that their contributions would be RANDZ. MarkM: If we can't formalize RANDZ in TC39 somehow, several members will desire to take the standards activity to an organization that can. Varied and long discussion about IPR policy developments.
ECMAScript(R) got registered as a trademark in Switzerland.
At next meeting MarkM will present a tiny API proposal for maps and sets. Allen: Reset agenda for next meeting. Don't include zombie carryovers. Brendan: Gavin is working on classes.
ArrayTypes: var Int8Array = new ArrayType(Int8); var arr1 = new Int8Array(100); var arr2 = new Int8Array(256);
var MyStruct = new StructType({extra: Int8Array(100)}); Note that Int8Array does different things when called with or without new. Debated how to do this -- specialize on new (can be done via proxies) or on whether the "this" value is undefined or not.
Allen, DaveH: Classes should support the ability to express APIs such as this one.
Waldemar: How would this work? let t = Int8Array(100); var arr3 = new t; Luke: It wouldn't. Some debate ensues. DaveH: There should be two kinds of array type objects: sized and unsized. Calling an unsized one as a function with a length argument returns a sized array type object. Can call new on the resulting sized array type to obtain an array instance. Luke now agrees.
Can construct an array value as a view over part of an ArrayBuffer. Waldemar: This brings up endian issues. Luke: Array buffer is exposed only if you allocate an array using an explicit ArrayBuffer. The forms that create arrays without explicit ArrayBuffers don't expose endianness. DaveH: The endianness ship has sailed with TypedArrays. It's implementation defined. DaveH: People use this to aid with file I/O. Waldemar: The two statements above contradict each other. All implementations will want to make the same choice to avoid nondeterministic behavior, particularly if people use it for file I/O. We should pick the main one and mandate it. Brendan: It's already specified as little endian for arrays and big endian for data view. Sam: Looked at the Kronos spec and it doesn't say anything about non-data-view endianness. It's not specified. DaveH: We should try to spec endianness if possible.
Debate over whether the following should be an error in strict mode (or "extended mode" if there is such a thing). It isn't an error in ES5.1 strict. function (e) {var e;} Consensus: No, we should not change strict mode incompatibly like this. This is valid in all modes. Brendan: It should be an early error to have a var hoist across a catch-block with the same variable name. Also, "function (e) {let e;}" should always be an error.
Allen, Sam: Module mode will be the same as strict mode, except possibly for additional free variable static checks.
Discussed Allen's list of current ES6 extended mode breaking changes from the "ES6 opt-in, reloaded" thread. Consensus: For each of these, either we introduce it in all code (maybe all strict code) or we don't do it.
Discussion about scope of for-bindings. for (var x = ...;;) {...} will, of course, retain ES1 semantics. for (let x = ...;;) {...} Allen: This will behave as in C++: x is bound once in a new scope immediately surrounding just the for statement. DaveH: Strangely enough, this creates a new x binding in Dart at each iteration. There's an alternative semantics that creates an iteration-local second x inside the loop and copies it back and forth. Debate about whether to go to such complexity. Many of us are on the fence. Waldemar: What happens in the forwarding semantics if you capture the x inside a lambda in any of the three expressions in the head? If this happens in the initializer: DaveH's option: The lambda would capture an outer x. Alternative: The lambda captures a hidden second x. Waldemar's option: The lambda would capture the x from the first iteration. The let variable x is bound once through each iteration, just before the test, if for (let x = expr1; expr2;) {...} were: while (true) { let x = first_iteration ? expr1 : value_of_x_from_previous_iteration; if (!expr2) break; ... } MarkM: Just discovered that his desugaring has the same semantics as Waldemar's option.
for (const x = ...;;) {...} behaves analogously to let, whatever we decide let will do.
Those opposed earlier to new-binding-per-iteration hop back onto the fence. Waldemar, Brendan, and DaveH hop off the fence to now support it, as it will cure an annoying gotcha in practice. Looks like we have support for it now.
End of meeting.