Request for feedback on a talk on I'm giving on ES6
(Attempting to send again with fewer URLs to avoid being spam-filtered? Apologies if this shows up twice.)
On Monday I'll be giving a talk about ES6 at EmpireJS. I just finished up my slides, and would love some feedback and critique from the es-discuss crew:
The slides consist primarily of code examples of almost every new feature, so accuracy checks and ES6-idiomaticness-improvements would be very helpful.
It has way too many slides for 30 minutes, so I'll be cutting large swathes of it to focus on those I classify as least-known but most-powerful. Nevertheless, feedback on all the slides would be lovely, given that I'll be using the rest of them in longer-form talks elsewhere. I also plan on submitting the code examples for inclusion in Dave's new wiki, or using them in other educational outreach efforts (e.g. blog posts), or even in a mini test suite so we can see how Chrome and Firefox's current implementations compare to the specced behavior.
Domenic Denicola wrote:
(Attempting to send again with fewer URLs to avoid being spam-filtered? Apologies if this shows up twice.)
On Monday I'll be giving a talk about ES6 at EmpireJS. I just finished up my slides, and would love some feedback and critique from the es-discuss crew:
The slides consist primarily of code examples of almost every new feature, so accuracy checks and ES6-idiomaticness-improvements would be very helpful.
Really nice slides! Good work.
Quick notes:
Slide 15 has a comment at the bottom: // error! used a let
before
declaration
but this error is about the most-indented log call, the one in the block
whose last child is 'let log = Math.log'. Perhaps you are going to talk
around it, but it seems to me a comment about an error should go right
where the error is.
Slide 29 nit: do you want to handle 1st, 2nd, and 3rd properly?
el.textContent = "The "+ i + ["th", "st", "nd", "rd"][i < 4? i : 0] + " <p>";
Slide 31 ends with a question: // what about module.exports= aFunction
?
Cc'ing dherman.
Slide 33 has a recursive call not in tail position:
functionsumTo(n) { return n ===0 ? 0 : n +sumTo(n -1); }
You might want to steal from www.owlnet.rice.edu/~comp210/96spring/Labs/lab09.html#SECTION00030000000000000000 by translating Scheme to JS.
Slides 34-35: do you want to show a multiline regexp with insignificant whitespace a la Perl's /x regex flag?
Slide 44 is good, a WeakMap beats a Map so you get automatic deletion when a given httpResponse dies. Could you show entries whose values might be keys (or parts of keys) of other entries? That would show the double-whammy.
Slide 46 has an iloop: maybe this is ok, or perhaps your next function should throw at some point. ;-)
Slide 48: Python mixes "Generator" to mean "the factory function" and "the generator-iterator it returns", and you do here. But "Generators make iterators" would be more precise in general, and in particular based on what this slide shows.
So slide 46 wants to say that @iterator names the iterator factory or getter (iterators return themselves). Can talk around this of course.
Looks great, more slides under construction? Need a rousing conclusion ;-).
Thanks so much for the feedback!
Domenic Denicola wrote:
Slide 31 ends with a question: // what about
module.exports= aFunction
? Cc'ing dherman.Yeah, since there will be lots of Node-ers there, and this is their #1 feature, I thought it was important to point out there's no solution for that yet. In general my impression is that modules are undergoing some rethinking and revision, especially about syntax. It's tricky, since even if I cut those slides, I want to e.g. import iterator, but am not sure what syntax to use :-/.
import iterator from "@iter";
is ok if you then use obj[iterator]. It may be we want to support both this and
import @iterator from "@iter";
which would support obj. at iterator = ... subsequently
Slide 33 has a recursive call not in tail position:
Damn, OK, I thought my example met the definition at proposals:proper_tail_calls (in particular "the only thing the caller can do when the call terminates" is "return the value of the call to its own caller"). It sounds like I don't quite understand tail recursion still, so thanks for the link---I'll brush up.
There's a + operation in flight in the caller.
On Sun, Oct 21, 2012 at 2:16 PM, Brendan Eich <brendan at mozilla.org> wrote:
Domenic Denicola wrote:
(Attempting to send again with fewer URLs to avoid being spam-filtered? Apologies if this shows up twice.)
On Monday I'll be giving a talk about ES6 at EmpireJS. I just finished up my slides, and would love some feedback and critique from the es-discuss crew:
jh2kcg.sn2.**livefilestore.com/y1pLp4Fh3CL9rp5A__EenS- TzdbQJMwG8IeIzQ_aRUbd6GakGmTcdBxx9Ec5SpKyfdHrD F0lFXr9sGfQJJVswnNAw/ES6%20is%**20Nigh.pdfjh2kcg.sn2.livefilestore.com/y1pLp4Fh3CL9rp5A__EenS-TzdbQJMwG8IeIzQ_aRUbd6GakGmTcdBxx9Ec5SpKyfdHrDF0lFXr9sGfQJJVswnNAw/ES6 is Nigh.pdf
The slides consist primarily of code examples of almost every new feature, so accuracy checks and ES6-idiomaticness-improvements would be very helpful.
Really nice slides! Good work.
Quick notes:
Slide 15 has a comment at the bottom: // error! used a
let
before declaration but this error is about the most-indented log call, the one in the block whose last child is 'let log = Math.log'. Perhaps you are going to talk around it, but it seems to me a comment about an error should go right where the error is.
nit: The comment itself says "// error! used a let
before declaration.",
might be nice to highlight that the error will occur until the let is
assigned, ie. I can initialize it, but reads will throw until it's assigned.
Not sure of the number, but there is a slide titled "Block Scoping" with this:
if (Math.random() > 0.5) { function go() { console.log("gone!"); } ... } assert(typeof go === "undefined");
I'm not sure I get what this one is trying to illustrate, because "go" will always be initialized, regardless of the condition
if (false) { function go() { console.log("gone!"); } } typeof go === "undefined"; // false
go(); // "gone!"
new Set(...document.body.children);
is a Syntax Error, use:
new Set([ ...document.body.children ]);
Same for: new Set(...array) Math.max(...array); Math.max(0, ...array, 5, ...array2); new Date(...dateFields); array.push(...array2);
I'm STOKED that you title Template Strings as such... good to get that word out.
new Set([...document.body.children])
Weak Sets aren't specified yet. Might be wise to omit that?
One of WeakMap's best use cases is private data...
(function(exports) { var priv = new WeakMap();
function C() { this.public = "hi!";
priv.set(this, { secret: "I will never tell!" }); }
C.prototype.guess = function( attempt ) { if ( priv.get(this).secret === attempt ) { // ...unlock } else { // ...stay locked } };
exports.C = C;
})(this);
... This way any number of methods, both on C's prototype or class-side functions, as long as they are defined in the same scope that "priv" is bound to, can access the private cache in "priv". This beats leaky plain object abstractions for a serious win :)
I'm not sure it's that important to talk about weaksets and weakmap. One or the other is enough assuming you've talked about maps and sets beforehand. In several slides, I see that you're using the following form:
var empireJS = {
preParty(){ // <-- this
console.log('');
}
}
What's the strawman related to this form? Is there an implementation of it in engines? I watch pretty much every presentation on ES6 that ends up in my Twitter stream and I don't recall seeing this form in presentations much. I however think it should be more heavily advertised. It's one way to get shorter functions that is not controversial :-)
Slide 14, extracting the log function doesn't work in Chrome, but does in Firefox. It might be safer to show a slide with console.log.bind(console)
For proxies, at the end, I would stick with the target/handler terminology for the sake of sharing a common terminology.
Otherwise, I like your slides. I really like how you've separated the different features, especially the "Magic" section :-)
David
2012/10/21 Domenic Denicola <domenic at domenicdenicola.com>
On Sun, Oct 21, 2012 at 5:58 PM, David Bruant <bruant.d at gmail.com> wrote:
Hi Domenic,
I'm not sure it's that important to talk about weaksets and weakmap. One or the other is enough assuming you've talked about maps and sets beforehand. In several slides, I see that you're using the following form:
var empireJS = { preParty(){ // <-- this console.log(''); } }
What's the strawman related to this form? Is there an implementation of it in engines?
David,
That's concise method definition and IIRC, the grammar is already in the current drafts
On Sun, Oct 21, 2012 at 5:58 PM, David Bruant <bruant.d at gmail.com> wrote:
Hi Domenic,
I'm not sure it's that important to talk about weaksets and weakmap. One or the other is enough assuming you've talked about maps and sets beforehand. In several slides, I see that you're using the following form:
var empireJS = { preParty(){ // <-- this console.log(''); } }
More specifically...
13.3 Method Definitions
*MethodDefinition *:
*PropertyName *( *FormalParameterList *) { *FunctionBody *}
Rick
I might steal "always bet on JS," or maybe I'll emphasize the way we can use these features today (SpiderMonkey, Chrome Embedded Frame or Node.js apps with flags, Traceur and other transpilers for the non-magic...). Still thinking on it, and of course toeing the sleep-dep/productivity line.
You could end by saying that in 6-8 months, CoffeeScript will be rendered moot by maturing ES6 transpilers. Stir the beehive! ; )
Thanks for your help Rick! I've corrected a few, but wasn't sure about some others. Let me know if I'm missing something in the following:
From: Rick Waldron [mailto:waldron.rick at gmail.com] Sent: Sunday, October 21, 2012 17:07
nit: The comment itself says "// error! used a
let
before declaration.", might be nice to highlight that the error will occur until the let is assigned, ie. I can initialize it, but reads will throw until it's assigned.
If I'm understanding you correctly, you're saying that this should throw?
let x;
assert(x === undefined); // error! Use of x
before it is assigned.
I was under the impression the temporal dead zone was about use-before-definition, not use-before-assignment. (For const they are the same, since the "Static Semantics: Early Errors" note on page 125 of the spec gives a Syntax Error if the Initialiser is omitted from the LexicalBinding.) That is:
"A let and const declarations define variables that are scoped to the running execution context’s LexicalEnvironment. The variables are created when their containing Lexical Environment is instantiated but may not be accessed in any way until the variable’s LexicalBinding is evaluated. A variable defined by a LexicalBinding with an Initialiser is assigned the value of its Initialiser’s AssignmentExpression when the LexicalBinding is evaluated, not when the variable is created. If a LexicalBinding in a let declaration does not have an an Initialiser the variable is assigned the value undefined when the LexicalBinding is evaluated."
This implies to me that the first line above evaluates the LexicalBinding, assigning the variable the value undefined; since the LexicalBinding is evaluated, the "may not be accessed" clause no longer applies, and no error should occur.
Not sure of the number, but there is a slide titled "Block Scoping" with this:
if (Math.random() > 0.5) { function go() { console.log("gone!"); } ... } assert(typeof go === "undefined");
I'm not sure I get what this one is trying to illustrate, because "go" will always be initialized, regardless of the condition
I believe this is not true. The current semantics for block-scoped functions bind them to the block, not to the surrounding function. (That is, a FunctionDeclaration creates an entry into LexicallyDeclaredNames, not into VarDeclaredNames.)
Even in ES5, this behavior is unspecified: see the "NOTE" under the "Semantics" heading under section 12 of ES5.1, where it notes that even though Statement does not include FunctionDeclaration, implementations often allow it, with "significant and irreconcilable variations." (So, I don't think "go" will always be initialized in all browsers. For example, in IE10 strict mode the above code is a SyntaxError.) It also says that "Future editions of ECMAScript may define alternative portable means for declaring functions in a Statement context."
And indeed, in ES6 the Declaration grammar production is introduced as a sibling to Statement under Block. It includes LexicalDeclaration and FunctionDeclaration; VariableStatements are left under Statement. And the Block Declaration Instantiation algorithm (10.5.4) includes both LexicalDeclarations and FunctionDeclarations, i.e. FunctionDeclarations are added to the block's Declarative Environment Record instead of to the environment record of the containing function.
new Set(...document.body.children);
is a Syntax Error, use:
new Set([ ...document.body.children ]);
Same for: new Set(...array) Math.max(...array); Math.max(0, ...array, 5, ...array2); new Date(...dateFields); array.push(...array2);
I don't think any of these is a syntax error, since spread works for function calls/constructs too. See tc39wiki.calculist.org/es6/spread or section 11.2.5 of the draft spec wherein the expanded runtime semantics for ArgumentListEvaluation are given (in particular ArgumentList: ...AssignmentExpression and ArgumentList: ArgumentList, ...AssignmentExpression). However, you are right that the sets should be constructed that way, since the Set constructor accepts an iterable and not varargs. Much appreciated!
Also, I just realized that in rearranging my slides I used spread before discussing it -_-. Will need to fix. Maybe "rest and spread" are more comfort than cowpath-paving...
Weak Sets aren't specified yet. Might be wise to omit that?
Yeah, probably a good place to trim the fat. They are harmonious though, right? Since they're necessary for revocable proxies.
One of WeakMap's best use cases is private data...
... This way any number of methods, both on C's prototype or class-side functions, as long as they are defined in the same scope that "priv" is bound to, can access the private cache in "priv". This beats leaky plain object abstractions for a serious win :)
The problem I've always had with this is that using weak maps for objects you control is silly, when you could just use symbols. Indeed I illustrate the symbol vs. weak map question in my "Symbols Again" slide. Weak maps are more correct for objects you don't control though, due to the possibility of extension-prevented objects (as I plan to point out when that slide comes up). But for the simple private data use case, symbols are great. I was really glad Brendan reminded me that the values are also held weakly, since otherwise weak maps just reduce to a more-cumbersome, but safer, version of symbols.
Again, thanks for your help, and see you tomorrow!
Thanks to all for the feedback. I incorporated as much as I could into the presentation, and I think got all the accuracy issues straightened out, pending potential misunderstandings of Rick's points. I posted both the unabridged version and the EmpireJS 30-minute version at
(or, if the DNS isn't working yet, domenic.github.com/es6isnigh).
Still much to do before I'd consider the full version "done": e.g. incorporate Brendan's template string regexes and weakly-held values examples, convert to HTML instead of PowerPoint/PDF, and so on. But it's a start! Now all I have left to do is actually get up on stage and present, heh.
I'll update the 30-minute slides throughout the day if anyone has remaining corrections or suggestions.
On Monday, October 22, 2012 at 1:04 AM, Domenic Denicola wrote:
Thanks for your help Rick! I've corrected a few, but wasn't sure about some others. Let me know if I'm missing something in the following:
From: Rick Waldron [mailto:waldron.rick at gmail.com]
Sent: Sunday, October 21, 2012 17:07nit: The comment itself says "// error! used a
let
before declaration.", might be nice to highlight that the error will occur until the let is assigned, ie. I can initialize it, but reads will throw until it's assigned.If I'm understanding you correctly, you're saying that this should throw?
let x; assert(x === undefined); // error! Use of
x
before it is assigned.
yes, any read access will throw before assignment.
I was under the impression the temporal dead zone was about use-before-definition, not use-before-assignment.
There is no deadzone in the former, it's use-before-assignment
(For const they are the same, since the "Static Semantics: Early Errors" note on page 125 of the spec gives a Syntax Error if the Initialiser is omitted from the LexicalBinding.) That is:
"A let and const declarations define variables that are scoped to the running execution context’s LexicalEnvironment. The variables are created when their containing Lexical Environment is instantiated but may not be accessed in any way until the variable’s LexicalBinding is evaluated. A variable defined by a LexicalBinding with an Initialiser is assigned the value of its Initialiser’s AssignmentExpression when the LexicalBinding is evaluated, not when the variable is created. If a LexicalBinding in a let declaration does not have an an Initialiser the variable is assigned the value undefined when the LexicalBinding is evaluated."
This implies to me that the first line above evaluates the LexicalBinding, assigning the variable the value undefined; since the LexicalBinding is evaluated, the "may not be accessed" clause no longer applies, and no error should occur.
I'm not sure the full temporal deadzone semantics are even in a draft yet (like lots of things)
Not sure of the number, but there is a slide titled "Block Scoping" with this:
if (Math.random() > 0.5) { function go() { console.log("gone!"); } ... } assert(typeof go === "undefined");
I'm not sure I get what this one is trying to illustrate, because "go" will always be initialized, regardless of the condition
I believe this is not true. The current semantics for block-scoped functions bind them to the block, not to the surrounding function. (That is, a FunctionDeclaration creates an entry into LexicallyDeclaredNames, not into VarDeclaredNames.) Even in ES5, this behavior is unspecified: see the "NOTE" under the "Semantics" heading under section 12 of ES5.1, where it notes that even though Statement does not include FunctionDeclaration, implementations often allow it, with "significant and irreconcilable variations." (So, I don't think "go" will always be initialized in all browsers. For example, in IE10 strict mode the above code is a SyntaxError.) It also says that "Future editions of ECMAScript may define alternative portable means for declaring functions in a Statement context."
And indeed, in ES6 the Declaration grammar production is introduced as a sibling to Statement under Block. It includes LexicalDeclaration and FunctionDeclaration; VariableStatements are left under Statement. And the Block Declaration Instantiation algorithm (10.5.4) includes both LexicalDeclarations and FunctionDeclarations, i.e. FunctionDeclarations are added to the block's Declarative Environment Record instead of to the environment record of the containing function.
new Set(...document.body.children);
is a Syntax Error, use:
new Set([ ...document.body.children ]);
Same for:
new Set(...array) Math.max(...array); Math.max(0, ...array, 5, ...array2); new Date(...dateFields); array.push(...array2);I don't think any of these is a syntax error, since spread works for function calls/constructs too. See tc39wiki.calculist.org/es6/spread or section 11.2.5 of the draft spec wherein the expanded runtime semantics for ArgumentListEvaluation are given (in particular ArgumentList: ...AssignmentExpression and ArgumentList: ArgumentList, ...AssignmentExpression). However, you are right that the sets should be constructed that way, since the Set constructor accepts an iterable and not varargs. Much appreciated!
Not according to SpiderMonkey, so someone has a bug.
Also, I just realized that in rearranging my slides I used spread before discussing it -_-. Will need to fix. Maybe "rest and spread" are more comfort than cowpath-paving...
Weak Sets aren't specified yet. Might be wise to omit that?
Yeah, probably a good place to trim the fat. They are harmonious though, right? Since they're necessary for revocable proxies.
They are, but no like I said, no spec yet
One of WeakMap's best use cases is private data...
... This way any number of methods, both on C's prototype or class-side functions, as long as they are defined in the same scope that "priv" is bound to, can access the private cache in "priv". This beats leaky plain object abstractions for a serious win :)
The problem I've always had with this is that using weak maps for objects you control is silly, when you could just use symbols. Indeed I illustrate the symbol vs. weak map question in my "Symbols Again" slide. Weak maps are more correct for objects you don't control though, due to the possibility of extension-prevented objects (as I plan to point out when that slide comes up). But for the simple private data use case, symbols are great. I was really glad Brendan reminded me that the values are also held weakly, since otherwise weak maps just reduce to a more-cumbersome, but safer, version of symbols.
It's not silly when you don't have symbols available.
Another better example is using a DOM node as a key to associate data
On Oct 22, 2012, at 5:27 AM, Rick Waldron wrote:
On Monday, October 22, 2012 at 1:04 AM, Domenic Denicola wrote:
Thanks for your help Rick! I've corrected a few, but wasn't sure about some others. Let me know if I'm missing something in the following:
From: Rick Waldron [mailto:waldron.rick at gmail.com] Sent: Sunday, October 21, 2012 17:07
nit: The comment itself says "// error! used a
let
before declaration.", might be nice to highlight that the error will occur until the let is assigned, ie. I can initialize it, but reads will throw until it's assigned.If I'm understanding you correctly, you're saying that this should throw?
let x; assert(x === undefined); // error! Use of
x
before it is assigned. yes, any read access will throw before assignment.I was under the impression the temporal dead zone was about use-before-definition, not use-before-assignment. There is no deadzone in the former, it's use-before-assignment
No, Domenic is correct. It is "use before initialization". Let bindings that lack an initializer have an implicit "=undefined" initializer.
(For const they are the same, since the "Static Semantics: Early Errors" note on page 125 of the spec gives a Syntax Error if the Initialiser is omitted from the LexicalBinding.) That is:
"A let and const declarations define variables that are scoped to the running execution context’s LexicalEnvironment. The variables are created when their containing Lexical Environment is instantiated but may not be accessed in any way until the variable’s LexicalBinding is evaluated. A variable defined by a LexicalBinding with an Initialiser is assigned the value of its Initialiser’s AssignmentExpression when the LexicalBinding is evaluated, not when the variable is created. If a LexicalBinding in a let declaration does not have an an Initialiser the variable is assigned the value undefined when the LexicalBinding is evaluated."
A missing initializer in a const declaration is defined as syntax error by the first Early Error rule in section 12.2.1 which is for the production LexicalBinding : BindingIdentifier
The note quoted above is an informative note and not normative language. What it describes is accurate but is expressed in a more precise, but less centralized manner by the normative algorithms and rules of the specification,
This implies to me that the first line above evaluates the LexicalBinding, assigning the variable the value undefined; since the LexicalBinding is evaluated, the "may not be accessed" clause no longer applies, and no error should occur.
I'm not sure the full temporal deadzone semantics are even in a draft yet (like lots of things)
Yes, it's are all there, at least for function level declarations. Of course, there could be errors so read deeply...
The global scope will be in the next draft.
Not sure of the number, but there is a slide titled "Block Scoping" with this:
if (Math.random() > 0.5) { function go() { console.log("gone!"); } ... } assert(typeof go === "undefined");
I'm not sure I get what this one is trying to illustrate, because "go" will always be initialized, regardless of the condition
I believe this is not true. The current semantics for block-scoped functions bind them to the block, not to the surrounding function. (That is, a FunctionDeclaration creates an entry into LexicallyDeclaredNames, not into VarDeclaredNames.) Even in ES5, this behavior is unspecified: see the "NOTE" under the "Semantics" heading under section 12 of ES5.1, where it notes that even though Statement does not include FunctionDeclaration, implementations often allow it, with "significant and irreconcilable variations." (So, I don't think "go" will always be initialized in all browsers. For example, in IE10 strict mode the above code is a SyntaxError.) It also says that "Future editions of ECMAScript may define alternative portable means for declaring functions in a Statement context."
And indeed, in ES6 the Declaration grammar production is introduced as a sibling to Statement under Block. It includes LexicalDeclaration and FunctionDeclaration; VariableStatements are left under Statement. And the Block Declaration Instantiation algorithm (10.5.4) includes both LexicalDeclarations and FunctionDeclarations, i.e. FunctionDeclarations are added to the block's Declarative Environment Record instead of to the environment record of the containing function.
Yes, function declarations are block scoped and are not hoisted to the surrounding function.
In the above example, the asset is outside the block that defines go, so the declaration is invisible. so, result is going to be just like ES5: either a Reference Error or undefined, depending upon rather it is strict mode or not.
new Set(...document.body.children);
is a Syntax Error, use:
new Set([ ...document.body.children ]);
Same for: new Set(...array) Math.max(...array); Math.max(0, ...array, 5, ...array2); new Date(...dateFields); array.push(...array2);
I don't think any of these is a syntax error, since spread works for function calls/constructs too. See tc39wiki.calculist.org/es6/spread or section 11.2.5 of the draft spec wherein the expanded runtime semantics for ArgumentListEvaluation are given (in particular ArgumentList: ...AssignmentExpression and ArgumentList: ArgumentList, ...AssignmentExpression). However, you are right that the sets should be constructed that way, since the Set constructor accepts an iterable and not varargs. Much appreciated! Not according to SpiderMonkey, so someone has a bug.
I just (yesterday) wrote the spec. language for Set and it takes a single optional iterable argument. I don't see anything
On Oct 22, 2012, at 5:27 AM, Rick Waldron wrote:
On Monday, October 22, 2012 at 1:04 AM, Domenic Denicola wrote:
Thanks for your help Rick! I've corrected a few, but wasn't sure about some others. Let me know if I'm missing something in the following:
From: Rick Waldron [mailto:waldron.rick at gmail.com] Sent: Sunday, October 21, 2012 17:07
nit: The comment itself says "// error! used a
let
before declaration.", might be nice to highlight that the error will occur until the let is assigned, ie. I can initialize it, but reads will throw until it's assigned.If I'm understanding you correctly, you're saying that this should throw?
let x; assert(x === undefined); // error! Use of
x
before it is assigned. yes, any read access will throw before assignment.I was under the impression the temporal dead zone was about use-before-definition, not use-before-assignment. There is no deadzone in the former, it's use-before-assignment
No, Domenic is correct. It is "use before initialization". Let bindings that lack an initializer have an implicit "=undefined" initializer.
(For const they are the same, since the "Static Semantics: Early Errors" note on page 125 of the spec gives a Syntax Error if the Initialiser is omitted from the LexicalBinding.) That is:
"A let and const declarations define variables that are scoped to the running execution context’s LexicalEnvironment. The variables are created when their containing Lexical Environment is instantiated but may not be accessed in any way until the variable’s LexicalBinding is evaluated. A variable defined by a LexicalBinding with an Initialiser is assigned the value of its Initialiser’s AssignmentExpression when the LexicalBinding is evaluated, not when the variable is created. If a LexicalBinding in a let declaration does not have an an Initialiser the variable is assigned the value undefined when the LexicalBinding is evaluated."
A missing initializer in a const declaration is defined as syntax error by the first Early Error rule in section 12.2.1 which is for the production LexicalBinding : BindingIdentifier
The note quoted above is an informative note and not normative language. What it describes is accurate but is expressed in a more precise, but less centralized manner by the normative algorithms and rules of the specification,
This implies to me that the first line above evaluates the LexicalBinding, assigning the variable the value undefined; since the LexicalBinding is evaluated, the "may not be accessed" clause no longer applies, and no error should occur.
I'm not sure the full temporal deadzone semantics are even in a draft yet (like lots of things)
Yes, it's are all there, at least for function level declarations. Of course, there could be errors so read deeply...
The global scope will be in the next draft.
Not sure of the number, but there is a slide titled "Block Scoping" with this:
if (Math.random() > 0.5) { function go() { console.log("gone!"); } ... } assert(typeof go === "undefined");
I'm not sure I get what this one is trying to illustrate, because "go" will always be initialized, regardless of the condition
I believe this is not true. The current semantics for block-scoped functions bind them to the block, not to the surrounding function. (That is, a FunctionDeclaration creates an entry into LexicallyDeclaredNames, not into VarDeclaredNames.) Even in ES5, this behavior is unspecified: see the "NOTE" under the "Semantics" heading under section 12 of ES5.1, where it notes that even though Statement does not include FunctionDeclaration, implementations often allow it, with "significant and irreconcilable variations." (So, I don't think "go" will always be initialized in all browsers. For example, in IE10 strict mode the above code is a SyntaxError.) It also says that "Future editions of ECMAScript may define alternative portable means for declaring functions in a Statement context."
And indeed, in ES6 the Declaration grammar production is introduced as a sibling to Statement under Block. It includes LexicalDeclaration and FunctionDeclaration; VariableStatements are left under Statement. And the Block Declaration Instantiation algorithm (10.5.4) includes both LexicalDeclarations and FunctionDeclarations, i.e. FunctionDeclarations are added to the block's Declarative Environment Record instead of to the environment record of the containing function.
Yes, function declarations are block scoped and are not hoisted to the surrounding function.
In the above example, the asset is outside the block that defines go, so the declaration is invisible. so, result is going to be just like ES5: either a Reference Error or undefined, depending upon rather it is strict mode or not.
new Set(...document.body.children);
is a Syntax Error, use:
new Set([ ...document.body.children ]);
Same for: new Set(...array) Math.max(...array); Math.max(0, ...array, 5, ...array2); new Date(...dateFields); array.push(...array2);
I don't think any of these is a syntax error, since spread works for function calls/constructs too. See tc39wiki.calculist.org/es6/spread or section 11.2.5 of the draft spec wherein the expanded runtime semantics for ArgumentListEvaluation are given (in particular ArgumentList: ...AssignmentExpression and ArgumentList: ArgumentList, ...AssignmentExpression). However, you are right that the sets should be constructed that way, since the Set constructor accepts an iterable and not varargs. Much appreciated! Not according to SpiderMonkey, so someone has a bug.
I just (yesterday) wrote the spec. language for Set and it takes a single optional iterable argument. I don't see anything
On Mon, Oct 22, 2012 at 5:27 AM, Rick Waldron <waldron.rick at gmail.com>wrote:
On Monday, October 22, 2012 at 1:04 AM, Domenic Denicola wrote:
Thanks for your help Rick! I've corrected a few, but wasn't sure about some others. Let me know if I'm missing something in the following:
From: Rick Waldron [mailto:waldron.rick at gmail.com] Sent: Sunday, October 21, 2012 17:07
nit: The comment itself says "// error! used a
let
before declaration.", might be nice to highlight that the error will occur until the let is assigned, ie. I can initialize it, but reads will throw until it's assigned.If I'm understanding you correctly, you're saying that this should throw?
let x; assert(x === undefined); // error! Use of
x
before it is assigned.yes, any read access will throw before assignment.
We are planning to revisit this once we get some performance measurements of the cost of the current semantics. But Rick's position contradicts my understanding of what the current semantics is. My understanding is the same as Domenic's original: the let declaration initializes x (in this case to undefined), so the following use is outside the temporal dead zone and succeeds.
I was under the impression the temporal dead zone was about use-before-definition, not use-before-assignment.
Yes.
There is no deadzone in the former, it's use-before-assignment
That is not my understanding.
On Mon, Oct 22, 2012 at 12:43 PM, Mark S. Miller <erights at google.com> wrote:
On Mon, Oct 22, 2012 at 5:27 AM, Rick Waldron <waldron.rick at gmail.com>wrote:
On Monday, October 22, 2012 at 1:04 AM, Domenic Denicola wrote:
Thanks for your help Rick! I've corrected a few, but wasn't sure about some others. Let me know if I'm missing something in the following:
From: Rick Waldron [mailto:waldron.rick at gmail.com] Sent: Sunday, October 21, 2012 17:07
nit: The comment itself says "// error! used a
let
before declaration.", might be nice to highlight that the error will occur until the let is assigned, ie. I can initialize it, but reads will throw until it's assigned.If I'm understanding you correctly, you're saying that this should throw?
let x; assert(x === undefined); // error! Use of
x
before it is assigned.yes, any read access will throw before assignment.
We are planning to revisit this once we get some performance measurements of the cost of the current semantics. But Rick's position contradicts my understanding of what the current semantics is. My understanding is the same as Domenic's original: the let declaration initializes x (in this case to undefined), so the following use is outside the temporal dead zone and succeeds.
My response was based on a re-reviewing the notes from Sept 20th. I'll accept that I've misunderstood the semantics... Apologies to Domenic for any confusion on this point.
On Monday I'll be giving a talk about ES6 at EmpireJS 1. I just finished up my slides, and would love some feedback and critique from the es-discuss crew:
tinyurl.com/es6isnighdraft
They consist primarily of code examples of almost every new feature, so accuracy checks and ES6-idiomaticness-improvements would be very helpful.
It has way too many slides for 30 minutes, so I'll be cutting large swathes of it to focus on those I classify as least-known but most-powerful. Nevertheless, feedback on all the slides would be lovely, given that I'll assuredly be using the rest of them in longer-form talks and also plan on submitting the code examples for inclusion in Dave's new wiki 2, or using them in other educational outreach efforts (e.g. blog posts).