Real World Func Decl in Block Scope Breakages
Thanks for the data.
My understanding of the consensus was that block-local functions would only have the new semantics within strict code (which includes module code), so there would be no breakage of existing content.
That said, if we felt the breakage was acceptable, in the long run it'd be preferable to have consistent semantics of block-local functions everywhere. Data like this certainly helps to make more informed decision about that.
On Dec 26, 2012, at 2:02 PM, David Herman wrote:
Hi Brian,
Thanks for the data.
My understanding of the consensus was that block-local functions would only have the new semantics within strict code (which includes module code), so there would be no breakage of existing content.
That isn't my understanding. Rather, it was that we would support block level function declarations in all code. This was based upon the premise that the interoperable intersection of the currently implemented semantics for block level function declarations is very small. Essentially only, uses of this form are currently interoperable among all major implementations:
if (condition) { function foo() {}; foo(); //function declared and invoked in same conditional blocks. }
Other uses (without other explicit feature or browser detection logic being involved) are not likely to be interoperable.
I haven't looked in detail at all of Brian's snippets. But several that I have glanced at look to me like they wouldn't be interoperable among current browsers.
Alen
This appears to be correct. A number of the examples can be boiled down to the following test:
if (false) {
function x(){
console.log('worked');
}
}
x();
In Chrome, IE, Opera, and Safari 'worked' will be logged. In Firefox it will silently fail.
Perhaps, but the mobile web is WebKitty. The ES6 semantics is incompatible with Chrome and Safari's behavior here.
Most of the snippets fall into either column 5 or 10 in the output table on this site[1] (which is down, hence cached copy, hopefully it works for you guys). These are mostly interoperable across browser.
From: es-discuss-bounces at mozilla.org [mailto:es-discuss-bounces at mozilla.org] On Behalf Of Brandon Benvie Sent: Wednesday, December 26, 2012 2:38 PM To: Allen Wirfs-Brock Cc: es-discuss at mozilla.org Subject: Re: Real World Func Decl in Block Scope Breakages
This appears to be correct. A number of the examples can be boiled down to the following test:
if (false) { function x(){ console.log('worked'); } } x();
In Chrome, IE, Opera, and Safari 'worked' will be logged. In Firefox it will silently fail.
On Wed, Dec 26, 2012 at 5:22 PM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:
Essentially only, uses of this form are currently interoperable among all major implementations:
if (condition) { function foo() {}; foo(); //function declared and invoked in same conditional blocks. }
Other uses (without other explicit feature or browser detection logic being involved) are not likely to be interoperable.
I haven't looked in detail at all of Brian's snippets. But several that I have glanced at look to me like they wouldn't be interoperable among current browsers.
Unless I'm mistaken on how Spidermonkey handles function declarations in block scope, almost none of those examples will work correctly in Firefox. Most of them will work in every other major browser, but not in Firefox. The question of whether the sites are actually broken in Firefox will mostly come down to whether the given code runs in Firefox or not.
Brian Terlson wrote:
20 sites, however, will likely be broken by this change in some way. There is also a chance that the tool used to identify breakages has missed some code that will breka.
Below are some examples of code on the web today that will be broken. For each I include a snippet of code that is heavily edited in an attempt to convey the pattern used and the developer intent. I also attempt to identify what functionality will actually be broken.
Thanks for the snippets. Some questions interspersed below.
Most of the breakages occur in non-library code, with two exceptions: qTip 1.0, and thickbox 3.
ninemsn.com.au
RenderModal = function () {
if (x) { // is an array of shortcuts that can be added. Is statically non-empty.
function K() {
// process the array of shortcuts in some way
}
}
K();
};
Since x evaluates as truthy no matter what (even an empty array is an object, therefore truthy), this is equivalent to
RenderModal = function () {
function K() {
// process the array of shortcuts in some way
}
K();
};
but of course it lies outside of ES6's function-in-block semantics, yet still in the intersection of Firefox and IE/IE-emulating-browsers.
yandex.ru
if (_ycssjs("BaH0Fmmo2Sg24lRmTPrK0B8qpaA")) {
function cp(g, c, d) { /* ...*/ }
function csh_ifgsid(c, b) { /.../ } }
// ... thousands of lines of code ...
This "then" block presumably closes here, before:
if (_ycssjs("rO+QIoSf2L0NwDn6vjJjy+27nxI")) {
function news() {
csh_if_gsid();
}
}
if (_ycssjs("YRPF0QVjJmhRiKRu6cvi3YXqYo8")) {
// ... bunch of stuff ...
cp();
}
Somehow the "if" conditions are logically connected such that no calls to an undefined identifier occur! Blech.
Scenario
Unknown
Indeed! Cc'ing Chaals in case he can shed light.
g.espncdn.com/nfl-primetime-payoff/en/module/entry?matchupid=478
if (isIE && isWin) {
// ...
} else {
function JSGetSwfVer(i){
// ...
}
}
function checkFlash(myRev) {
// ...
if (isIE && isWin) {
// ...
} else {
aV = JSGetSwfVer(rV);
}
}
Scenario
Can’t find a page which uses this code.
Can you say how many of the 20 cases involve actual live code using the function-in-pre-ES6-block code?
www.t-online.de
if (!Adition_Environment) {
var Adition_Environment = (function () {
var _this = {};
// ...
_this.getPrf = function (cuId) {
var prf = "";
try {
prf = Adition_Prfstr(cuId);
} catch (e) { }
return prf;
};
// ...
})();
}
// snip 1k lines
if (typeof Adition_Prfstr == "undefined") {
function Adition_Prfstr(ADITION_CONTENTUNIT_ID) {
// ...
}
}
Scenario
Required to display advertisements on the page.
Heinous.
manormystery.com
if (!window._ate) {
window._ate = { /* ... */ };
function addthis_open() { /* ... */ } } else { _ate.inst++; }
Did you snip the closing brace for the "then" block left open, the one for "if (!window._ate)"?
if (_atc.abf) {
addthis_open(document.getElementById("ab"), "emailab", window.addthis_url || "[URL]", window.addthis_title || "[TITLE]"); }
Scenario
Social sharing popups broken at least. This may be a general utility used in a number of places.
On the other hand, the snippet seems like a mis-coding of
if (!window._ate) {
window._ate = { /* ... */ };
}
function addthis_open() { /* ... */ } } else { _ate.inst++; }
if (_atc.abf) {
addthis_open(document.getElementById("ab"), "emailab", window.addthis_url || "[URL]", window.addthis_title || "[TITLE]"); }
... }
I'd try to evangelize the owner of this code.
manhunt.net (NSFW, DO NOT VISIT AT WORK)
/** @todo isFlashInstalled() should probably be gotten by include from js/cmmn/flashDetect.js or upfunc.js. */
if (typeof isFlashInstalled == 'undefined') {
function isFlashInstalled() {
var requiredMajorVersion = 6; // Major version of Flash required
var requiredMinorVersion = 0; // Minor version of Flash required
var requiredRevision = 0; // Minor version of Flash required
var s = new SWFObject();
if (!s) return false;
var version = s.installedVer;
if (!version) return false;
return (version.major >= requiredMajorVersion && version.minor >= requiredMinorVersion && version.rev >= requiredRevision);
}
}
isFlashInstalled();
Here is the simplest example of a pre-ES6 Firefox/IE+clones intersection: function-in-block with hoisting to top of outer function or global scope and SpiderMonkey's assignment-like runtime binding both work the same, provided the use(s) of the function's name all occur after any such assignment (in the SpiderMonkey in Firefox scenario).
There's no control flow relation in general, e.g. dominance. However in this case the "if (typeof isFlashInstalled == 'undefined')" head could, to a sufficiently smart CFG analyzer, imply that isFlashInstalled() post-dominates some kind of "definition" of that name.
Ok, enough so far to say a few things:
-
We have time and (among the bigs involved in ES6) try evangelization. Evangelization can be crowd-sourced too, and can be more effective when done that way.
-
We have some terrible choices, even if ES6's function-in-block semantics require "use strict". That leaves the above mess a de-facto standard which has never been specified. Specifying the sloppy-mode intersection is going to be ugly and a time-sink.
-
The carrot of function-in-block may be sweet -- we have evidence in all the good sites your crawl found that are not the insane 20 -- but whether "use strict"; required before all such ES6 function-in-block uses would be a stick remains to be investigated. Did you check for "use strict" or actual enabled-in-IE10 strict mode among the sites you found that declare functions in blocks?
Responses inline.
-----Original Message----- From: Brendan Eich [mailto:brendan at mozilla.com] Sent: Wednesday, December 26, 2012 3:27 PM To: Brian Terlson Cc: es-discuss at mozilla.org; Charles McCathie Nevile Subject: Re: Real World Func Decl in Block Scope Breakages
Brian Terlson wrote:
20 sites, however, will likely be broken by this change in some way. There is also a chance that the tool used to identify breakages has missed some code that will breka.
Below are some examples of code on the web today that will be broken. For each I include a snippet of code that is heavily edited in an attempt to convey the pattern used and the developer intent. I also attempt to identify what functionality will actually be broken.
Thanks for the snippets. Some questions interspersed below.
Most of the breakages occur in non-library code, with two exceptions: qTip 1.0, and thickbox 3.
ninemsn.com.au
RenderModal = function () {
if (x) { // is an array of shortcuts that can be added. Is statically non-empty.
function K() {
// process the array of shortcuts in some way
}
}
K();
};
Since x evaluates as truthy no matter what (even an empty array is an object, therefore truthy), this is equivalent to
RenderModal = function () {
function K() {
// process the array of shortcuts in some way
}
K();
};
but of course it lies outside of ES6's function-in-block semantics, yet still in the intersection of Firefox and IE/IE-emulating-browsers.
yandex.ru
if (_ycssjs("BaH0Fmmo2Sg24lRmTPrK0B8qpaA")) {
function cp(g, c, d) { /* ...*/ }
function csh_ifgsid(c, b) { /.../ } }
// ... thousands of lines of code ...
This "then" block presumably closes here, before:
if (_ycssjs("rO+QIoSf2L0NwDn6vjJjy+27nxI")) {
function news() {
csh_if_gsid();
}
}
if (_ycssjs("YRPF0QVjJmhRiKRu6cvi3YXqYo8")) {
// ... bunch of stuff ...
cp();
}
Somehow the "if" conditions are logically connected such that no calls to an undefined identifier occur! Blech.
Scenario
Unknown
Indeed! Cc'ing Chaals in case he can shed light.
g.espncdn.com/nfl-primetime- payoff/en/module/entry?matchupid=47 8
if (isIE && isWin) {
// ...
} else {
function JSGetSwfVer(i){
// ...
}
}
function checkFlash(myRev) {
// ...
if (isIE && isWin) {
// ...
} else {
aV = JSGetSwfVer(rV);
}
}
Scenario
Can't find a page which uses this code.
Can you say how many of the 20 cases involve actual live code using the function-in-pre-ES6-block code?
Just going by the snippets that have a known scenario rather than unknown, looks like 10/20. For the others, I do not know for sure whether the snippet is dead code or not. If you have any suggestions for how I could determine this more easily than heavily using the site under instrumentation I can look into collecting that data before the Jan meeting.
www.t-online.de
if (!Adition_Environment) {
var Adition_Environment = (function () {
var _this = {};
// ...
_this.getPrf = function (cuId) {
var prf = "";
try {
prf = Adition_Prfstr(cuId);
} catch (e) { }
return prf;
};
// ...
})();
}
// snip 1k lines
if (typeof Adition_Prfstr == "undefined") {
function Adition_Prfstr(ADITION_CONTENTUNIT_ID) {
// ...
}
}
Scenario
Required to display advertisements on the page.
Heinous.
manormystery.com
if (!window._ate) {
window._ate = { /* ... */ };
function addthis_open() { /* ... */ } } else { _ate.inst++; }
Did you snip the closing brace for the "then" block left open, the one for "if (!window._ate)"?
if (_atc.abf) {
addthis_open(document.getElementById("ab"), "emailab", window.addthis_url || "[URL]", window.addthis_title || "[TITLE]"); }
Scenario
Social sharing popups broken at least. This may be a general utility used in a number of places.
On the other hand, the snippet seems like a mis-coding of
if (!window._ate) {
window._ate = { /* ... */ };
}
function addthis_open() { /* ... */ } } else { _ate.inst++; }
if (_atc.abf) {
addthis_open(document.getElementById("ab"), "emailab", window.addthis_url || "[URL]", window.addthis_title || "[TITLE]"); }
... }
I'd try to evangelize the owner of this code.
manhunt.net (NSFW, DO NOT VISIT AT WORK)
/** @todo isFlashInstalled() should probably be gotten by include from js/cmmn/flashDetect.js or upfunc.js. */
if (typeof isFlashInstalled == 'undefined') {
function isFlashInstalled() {
var requiredMajorVersion = 6; // Major version of Flash required
var requiredMinorVersion = 0; // Minor version of Flash required
var requiredRevision = 0; // Minor version of Flash required
var s = new SWFObject();
if (!s) return false;
var version = s.installedVer;
if (!version) return false;
return (version.major >= requiredMajorVersion && version.minor >= requiredMinorVersion && version.rev >= requiredRevision);
}
}
isFlashInstalled();
Here is the simplest example of a pre-ES6 Firefox/IE+clones intersection: function-in-block with hoisting to top of outer function or global scope and SpiderMonkey's assignment-like runtime binding both work the same, provided the use(s) of the function's name all occur after any such assignment (in the SpiderMonkey in Firefox scenario).
There's no control flow relation in general, e.g. dominance. However in this case the "if (typeof isFlashInstalled == 'undefined')" head could, to a sufficiently smart CFG analyzer, imply that isFlashInstalled() post-dominates some kind of "definition" of that name.
Ok, enough so far to say a few things:
We have time and (among the bigs involved in ES6) try evangelization. Evangelization can be crowd-sourced too, and can be more effective when done that way.
We have some terrible choices, even if ES6's function-in-block semantics require "use strict". That leaves the above mess a de-facto standard which has never been specified. Specifying the sloppy-mode intersection is going to be ugly and a time-sink.
The carrot of function-in-block may be sweet -- we have evidence in all the good sites your crawl found that are not the insane 20 -- but whether "use strict"; required before all such ES6 function-in-block uses would be a stick remains to be investigated. Did you check for "use strict" or actual enabled- in-IE10 strict mode among the sites you found that declare functions in blocks?
Programmers do seem to want func decls in block scope a lot more than I expected, although I wouldn't necessarily call all non-breaking instances of it I found "sane" (eg. the decls I found in while/for statements...), just less insane :)
I didn't check for "use strict". I will work on capturing this data at least in time for the Jan meeting.
As far as IE doc modes, 15/19 are in standards mode (Zoompanel.com, Kankan.com, 163.com, and Verizon.com run in some compat mode). Didn't check the NSFW site.
Sorry, missed one question in there:
-----Original Message----- From: es-discuss-bounces at mozilla.org [mailto:es-discuss- bounces at mozilla.org] On Behalf Of Brian Terlson Sent: Wednesday, December 26, 2012 4:13 PM To: Brendan Eich Cc: Charles McCathie Nevile; es-discuss at mozilla.org Subject: RE: Real World Func Decl in Block Scope Breakages
Hi Brendan,
Responses inline.
-----Original Message----- From: Brendan Eich [mailto:brendan at mozilla.com] Sent: Wednesday, December 26, 2012 3:27 PM To: Brian Terlson Cc: es-discuss at mozilla.org; Charles McCathie Nevile Subject: Re: Real World Func Decl in Block Scope Breakages
Brian Terlson wrote:
20 sites, however, will likely be broken by this change in some way. There is also a chance that the tool used to identify breakages has missed some code that will breka.
Below are some examples of code on the web today that will be broken. For each I include a snippet of code that is heavily edited in an attempt to convey the pattern used and the developer intent. I also attempt to identify what functionality will actually be broken.
Thanks for the snippets. Some questions interspersed below.
Most of the breakages occur in non-library code, with two exceptions: qTip 1.0, and thickbox 3.
ninemsn.com.au
RenderModal = function () {
if (x) { // is an array of shortcuts that can be added. Is statically non-empty.
function K() {
// process the array of shortcuts in some way
}
}
K();
};
Since x evaluates as truthy no matter what (even an empty array is an object, therefore truthy), this is equivalent to
RenderModal = function () {
function K() {
// process the array of shortcuts in some way
}
K();
};
but of course it lies outside of ES6's function-in-block semantics, yet still in the intersection of Firefox and IE/IE-emulating-browsers.
yandex.ru
if (_ycssjs("BaH0Fmmo2Sg24lRmTPrK0B8qpaA")) {
function cp(g, c, d) { /* ...*/ }
function csh_ifgsid(c, b) { /.../ } }
// ... thousands of lines of code ...
This "then" block presumably closes here, before:
if (_ycssjs("rO+QIoSf2L0NwDn6vjJjy+27nxI")) {
function news() {
csh_if_gsid();
}
}
if (_ycssjs("YRPF0QVjJmhRiKRu6cvi3YXqYo8")) {
// ... bunch of stuff ...
cp();
}
Somehow the "if" conditions are logically connected such that no calls to an undefined identifier occur! Blech.
Scenario
Unknown
Indeed! Cc'ing Chaals in case he can shed light.
g.espncdn.com/nfl-primetime- payoff/en/module/entry?matchupid=47 8
if (isIE && isWin) {
// ...
} else {
function JSGetSwfVer(i){
// ...
}
}
function checkFlash(myRev) {
// ...
if (isIE && isWin) {
// ...
} else {
aV = JSGetSwfVer(rV);
}
}
Scenario
Can't find a page which uses this code.
Can you say how many of the 20 cases involve actual live code using the function-in-pre-ES6-block code?
Just going by the snippets that have a known scenario rather than unknown, looks like 10/20. For the others, I do not know for sure whether the snippet is dead code or not. If you have any suggestions for how I could determine this more easily than heavily using the site under instrumentation I can look into collecting that data before the Jan meeting.
www.t-online.de
if (!Adition_Environment) {
var Adition_Environment = (function () {
var _this = {};
// ...
_this.getPrf = function (cuId) {
var prf = "";
try {
prf = Adition_Prfstr(cuId);
} catch (e) { }
return prf;
};
// ...
})();
}
// snip 1k lines
if (typeof Adition_Prfstr == "undefined") {
function Adition_Prfstr(ADITION_CONTENTUNIT_ID) {
// ...
}
}
Scenario
Required to display advertisements on the page.
Heinous.
manormystery.com
if (!window._ate) {
window._ate = { /* ... */ };
function addthis_open() { /* ... */ } } else { _ate.inst++; }
Did you snip the closing brace for the "then" block left open, the one for "if (!window._ate)"?
The formatting is really bad due to a botched HTML-->plaintext conversion but it's there after the addthis_open decl.
Brandon Benvie wrote:
This appears to be correct. A number of the examples can be boiled down to the following test:
if (false) {
No, the working examples in Brian's snippets rather test an always-true condition. That means they work in Firefox too.
Brandon Benvie wrote:
Unless I'm mistaken on how Spidermonkey handles function declarations in block scope, almost none of those examples will work correctly in Firefox. Most of them will work in every other major browser, but not in Firefox.
No, that's not so. The ancient (pre-ES3) SpiderMonkey function-in-block semantics are like an assignment expression in effect, so if control flow reaches the nested function declaration, the var-like binding will be created and initialized. If control flow does not reach one of N possible for a given name, then the var-like binding won't even exist.
Crazy but true.
The snippets Brian posted all look like they'll work in SpiderMonkey / Firefox, at a glance from me. Let me know if I missed something.
My tests basically indicate what you said, but with a minor distinction. They don't fail outright, as in throw an error. They just fail silently. As in, it's ok to call the identifier, but it's not going to do anything. This is a curious Schrodinger's cat kind of intermediate state, where it doesn't succeed in doing what it was asked, but doesn't throw an error either, which in JS terms means it air-quotes succeeded but didn't really.
Brandon Benvie wrote:
My tests basically indicate what you said, but with a minor distinction. They don't fail outright, as in throw an error. They just fail silently. As in, it's ok to call the identifier, but it's not going to do anything.
No, something else is wrong. Can you show such a (reduced, I take it) testcase?
This is a curious Schrodinger's cat kind of intermediate state, where it doesn't succeed in doing what it was asked, but doesn't throw an error either, which in JS terms means it air-quotes succeeded but didn't really.
SpiderMonkey's function-in-block does not create any such magic error-free behavior. I don't know what you're seeing, but it's not what I saw at a glance, and not what SpiderMonkey implements for f-i-b.
if I run this code in the tools > web developer > web console, I get a
result of undefined and no error
if (false) { function x(){ console.log('worked') } } x();
[[bcc'ing es-discuss since this is a tangent.]
Well, bcc'ing didn't work -- mailman does not respect. Resending for posterity.
/be]
Brandon Benvie wrote:
if I run this code in the tools > web developer > web console, I get a result of undefined and no error
if (false) { function x(){ console.log('worked') } } x();
Best to test other ways than consoles, they do odd things in some browsers. But what you see is what I see when I load the content wrapped in script tags from /tmp/foo.html as well:
<script> if (false) { function x(){ console.log('worked') } } x() </script>
So Firefox is eating the error just as the console is. Not so a SpiderMonkey shell:
js> if (false) { function x(){ console.log('worked') } } x()
typein:1:53 ReferenceError: x is not defined
Let's try onerror:
<script> this.onerror = function(s) { alert('onerror: ' + s); } if (false) { function x(){ console.log('worked') } } x() </script>
Not sure what's up with the non-error, but the REPL shows a ReferenceError as expected. Could you please file a bug cc'ing me, dmandelin at mozilla.com, and :bz? Thanks.
Brendan Eich wrote:
Brandon Benvie wrote:
Unless I'm mistaken on how Spidermonkey handles function declarations in block scope, almost none of those examples will work correctly in Firefox. Most of them will work in every other major browser, but not in Firefox.
No, that's not so. The ancient (pre-ES3) SpiderMonkey function-in-block semantics are like an assignment expression in effect, so if control flow reaches the nested function declaration, the var-like binding will be created and initialized.
Astute students of ECMA-262 such as yourself probably see the contradiction above: "assignment" != "definition". Indeed I started with assignment ages ago but the code evolved to conditionally define (not run global setter for same-named property for function-in-block-in-global-code).
Anyway, the major point remains: the definition (originally, assignment) happens only if control flow reaches the nested declaration.
Brendan Eich wrote:
- We have time and (among the bigs involved in ES6)
"money"
try evangelization. Evangelization can be crowd-sourced too, and can be more effective when done that way.
Left out a word there ahem.
Boris Zbarsky mailed that this is fixed in Firefox Nightly, Brandon was in on that email, but I just wanted to confirm that I was testing Firefox 17.0.1 and it swallowed the ReferenceError, but my fresh test in Firefox Nightly logs the ReferenceError as expected (alerts with the onerror mod I show below).
All's well that ends well, but I'd still like to be cc'ed on that bug.
Le 27/12/2012 03:07, Brandon Benvie a écrit :
if I run this code in the tools > web developer > web console, I get a result of undefined and no error
if (false) { function x(){ console.log('worked') } } x();
I see an error on Firefox Aurora 19 WebConsole on Linux. I also see it when I put the code between <script>.
I don't know if it's related with your case, but last I checked, the Firefox WebConsole had its own global (different from the content global). Something to keep in mind when playing with subtle ECMAScript things (like here, declaring a global function).
Charles McCathie Nevile wrote:
On Thu, 27 Dec 2012 00:26:48 +0100, Brendan Eich <brendan at mozilla.com> wrote:
Brian Terlson wrote:
20 sites, however, will likely be broken by this change in some way.
I am guessing this is the key point. But there is a scope error, and "this" is undefined. It seems you're trying to find out why we are one of the few sites that do something, because you'd like to change something in ES that would break what we are doing, right? I am not sure exactly what the something or the change are, and that makes it hard for me to find the person who knows the answer (yes, folks, I confess that I didn't write this particular bit of code and haven't even carefully deconstructed it in my head.... ;) ).
So, any more clues? (No list-archive header to follow :( I can of course search, but someone here might be able to give a better reply more efficiently).
Sure, and sorry for lack of context.
The issue is that
function foo() { return 42; }
and
var foo = function() { return 42; }
and variations on the latter function expression syntax are all standardized. However,
if (cond) { function bar() { return 43; } } console.log(bar());
is not standardized. This syntax is not produced the any ECMA-262 standard grammar, but it is supported by all major implementations, with varying semantics. Call it function-in-block (f-i-b for short).
In IE and browsers that reverse-engineered IE JScript's implementation of f-i-b, bar is hoisted whether cond evaluates to truthy or falsy, so the console.log(bar()) always works.
In SpiderMonkey in Firefox and other apps, only if cond evaluates to truthy will bar be defined, leaving the bar() call within the console.log(bar()) expression possibly failing due to bar not being found in the scope chain, or resolving to an outer bar that might not be callable.
There is also a chance that the tool used to identify breakages has missed some code that will breka.
Below are some examples of code on the web today that will be broken. For each I include a snippet of code that is heavily edited in an attempt to convey the pattern used and the developer intent. I also attempt to identify what functionality will actually be broken.
What is the proposed change?
ES6 proposes that f-i-b always bind bar in the nearest enclosing curly-braced block, hoisted in the manner of function in JS today but to block scope, not function or program scope, so that the function can be used in expressions evaluated before control flows to evaluate the declaration of bar.
This means the example can fail if !cond. Only within the "then" block (anywhere, thanks to hoisting) could one safely use bar to mean the function declared within that block.
Clearly we had an incompatible change in mind. The fallback if we can't get away with this compat-break is to have ES6's f-i-b semantics only under "use strict" and have the old mess (browser-dependent) in non-strict ("sloppy") mode code.
Any help you can give on the one of 20 hard cases Brian found will be gratefully received.
Brendan Eich wrote:
What is the proposed change?
ES6 proposes that f-i-b always bind bar in the nearest enclosing curly-braced block, hoisted in the manner of function in JS today but to block scope, not function or program scope, so that the function can be used in expressions evaluated before control flows to evaluate the declaration of bar.
This means the example can fail if !cond.
Argh, meant to write "even if (cond)" -- i.e. the example will fail because the call to bar() after then if-then cannot possibly call the inner bar defined in the "then" bllock, in the ES6-proposed semantics.
Only within the "then" block (anywhere, thanks to hoisting) could one safely use bar to mean the function declared within that block.
I got this sentence right :-|.
HTH,
I have some data on patterns and sites that may break due to the proposed change to semantics of function decls in block scope. I am not advocating for any changes here but merely dumping some data I've gathered. I will continue gathering data about this breaking change and potentially others (eg. let[x] = 1), so any further data you folks are interested in let me know. I think the January meeting would be a good venue to discuss any of this in detail if warranted.
On December 17th, 2235 sites were crawled and their scripts downloaded. These scripts were then processed in an attempt to identify likely breakages due to the change to the semantics of func decls in block scope. In this dataset, 4% of the scripts contained a function declaration in block scope (mostly inside if and try, although pretty much every node contains a function somewhere in this dataset). However, most of these scripts use the function within the same block and so won't be broken. 20 sites, however, will likely be broken by this change in some way. There is also a chance that the tool used to identify breakages has missed some code that will breka.
Below are some examples of code on the web today that will be broken. For each I include a snippet of code that is heavily edited in an attempt to convey the pattern used and the developer intent. I also attempt to identify what functionality will actually be broken.
Most of the breakages occur in non-library code, with two exceptions: qTip 1.0, and thickbox 3.
ninemsn.com.au
RenderModal = function () {
};
Scenario
yandex.ru
if (_ycssjs("BaH0Fmmo2Sg24lRmTPrK0B8qpaA")) {
// ... thousands of lines of code ...
if (_ycssjs("rO+QIoSf2L0NwDn6vjJjy+27nxI")) {
}
if (_ycssjs("YRPF0QVjJmhRiKRu6cvi3YXqYo8")) {
}
Scenario
Unknown
g.espncdn.com/nfl-primetime-payoff/en/module/entry?matchupid=478
if (isIE && isWin) {
} else {
}
function checkFlash(myRev) {
}
Scenario
Can't find a page which uses this code.
www.t-online.de
if (!Adition_Environment) {
}
// snip 1k lines
if (typeof Adition_Prfstr == "undefined") {
}
Scenario
Required to display advertisements on the page.
manormystery.com
if (!window._ate) {
if (_atc.abf) {
Scenario
Social sharing popups broken at least. This may be a general utility used in a number of places.
manhunt.net (NSFW, DO NOT VISIT AT WORK)
/** @todo isFlashInstalled() should probably be gotten by include from js/cmmn/flashDetect.js or upfunc.js. */
if (typeof isFlashInstalled == 'undefined') {
}
isFlashInstalled();
Scenario
I avoided this site at work for obvious reasons, but it looks like all login functionality will be broken.
www.163.com
NTESAD_Couplet.prototype = {
}
Scenario
Unknown.
www22.verizon.com
if (floatStyle.match(/Content/)) {
}
// getRightOfContent/fixBackground used repeatedly after this.
Scenario
Couldn't find a scenario where this code was hit, but the site is expansive. Also, the above code is found in at least 2 different scripts across the site.
www.jeuxvideo.com
if (typeof getAppNexusMegaTag == 'undefined' || typeof getAppNexusMegaTag != 'function') {
}
if (typeof inFIF != "undefined" && inFIF == true) {
}
Scenario
Ad won't display.
msn.foxsports.com
/* this function is much faster, so if possible we use it. Some IEs are the only ones I know of that need the idiotic second function, generated by an if clause. */ function add32(a, b) {
}
if (md5('hello') != '5d41402abc4b2a76b9719d911017c592') {
}
Scenario
Nothing is necessary broken about this, as long as the first add32 functions properly (today everyone with this code is using the second function). This is a fairly common MD5 library (do a search for "idiotic second function" to get an idea, however this was only found once in the dataset).
iwiw.hu/i/belepes
(function () {
})();
Scenario
Unknown
www.laposte.net
if (!window.$extend) {
}
// $extend used repeatedly after this
Scenario
Unknown
atpworldtour.com
/*
Stores hash values for localization.
Will need duplicating for each language.
*/
if (typeof registerNS == "undefined") {
}
registerNS("atp.utilities");
// called repeatedly after this.
Scenario
Entire site is unusable.
atwiki.jp
if (typeof AddClipsFlag == "undefined") {
}
AddClipsLoad();
Scenario
RSS functionality broken. This appears to be a library of some kind (see www.addclips.orgwww.addclips.org).
Library: qTip 1.0: Craga89/qTip1/blob/master/1.0.0-rc3/jquery.qtip-1.0.0-rc3.js as seen on Zoompanel.com
if (t.options.hide.when.event == "inactive") {
} else {
}
function x(z) {
}
Scenario
Used on zoompanel.com. Tooltips will never disappear after showing up.
Library: thickbox 3 (thickbox.net), in use on runescape.com and baixaki.com.br if (!(TB_PrevHTML === "")) {
}
if (!(TB_NextHTML === "")) {
}
document.onkeydown = function (e) {
}
Scenario
Going back/forward with keyboard is broken.
kankan.com
Snippet
if (typeof getCookie == 'undefined') {
}
// ...
if (getCookie('tpar')) {
Scenario
Unknown, possibly just for tracking purposes.
Google +1 library (only seen on TMZ.com, possibly this lib is out of date) try {
} catch (e) { }
try {
Scenario
Plus one button is broken.