BTF Measurements
Kevin Smith wrote:
For the surveyed code, the percentage of function expressions which do not reference "this" ranges between 31% and 87%. About half of all function expressions are suitable for conversion to BTFs. Clearly BTFs would offer immediate quantifiable benefit.
This is good work, but I don't think every function that doesn’t use 'this' is a supporting use case for bound-this functions, though. Many functions are like this:
panels.each(function (p) { p.fadeIn(); });
and that function would not benefit at all from being converted to a bound-this function.
A function is only a use case for BTF if it also does use the enclosing function's 'this' somehow. That's harder to detect statically, but even harder to find is the code that gets rewritten a different way because of this-binding. :-\
Of the surveyed code, about 19% of BTF candidates contain a return statement as their first statement. This suggests that BTF syntax should be optimized for both "expression functions" and multi-statement function bodies, but with a preference given to multi-statement functions.
This is great data to have.
Something I found really interesting about this is that if you delete Facebook and Netflix, this number goes up to 27%. In the MooTools code, it's 40%. So either it just varies wildly depending on programming style, or else library code has a greater need for "expression functions" than application code.
Of the "expression functions", only 1.5% return an object literal. This suggests that BTF syntax should give preference to other forms, if there is a conflict.
This is good to know, too.
This is good work, but I don't think every function that doesn’t use 'this' is a supporting use case for bound-this functions, though. Many functions are like this:
panels.each(function (p) { p.fadeIn(); });
and that function would not benefit at all from being converted to a bound-this function.
Depending on syntax, it could be rewritten like this:
panels.each(p => { p.fadeIn(); });
which would offer gains in brevity, even though lexical this is not used. I'm assuming that for all "non-method" function expressions, BTFs would be preferred for this reason.
Kevin Smith wrote:
This is good work, but I don't think every function that doesn’t use 'this' is a supporting use case for bound-this functions, though. Many functions are like this: panels.each(function (p) { p.fadeIn(); }); and that function would not benefit at all from being converted to a bound-this function.
Depending on syntax, it could be rewritten like this:
panels.each(p => { p.fadeIn(); });
which would offer gains in brevity, even though lexical this is not used. I'm assuming that for all "non-method" function expressions, BTFs
The question here is, if there is a observable difference in performance between BTF and non-BTF, and not to allow the shorter syntax only for the less performant one (either only for the more performant one, or for both), because shorter form will be used also when not needed.
On Tue, Mar 13, 2012 at 8:43 AM, Herby Vojčík <herby at mailbox.sk> wrote:
Kevin Smith wrote:
[...] that function would not benefit at all from being converted to a bound-this function.
Depending on syntax, it could be rewritten like this:
panels.each(p => { p.fadeIn(); });
which would offer gains in brevity, even though lexical this is not used. I'm assuming that for all "non-method" function expressions, BTFs
The question here is, if there is a observable difference in performance between BTF and non-BTF, and not to allow the shorter syntax only for the less performant one (either only for the more performant one, or for both), because shorter form will be used also when not needed.
Hi Herby, the question where? Kevin is asking the question that I'm more interested in, and for the right reason. We're trying to figure out what the relative needs are for different forms of shorter function syntax.
The question here is, if there is a observable difference in performance between BTF and non-BTF, and not to allow the shorter syntax only for the less performant one (either only for the more performant one, or for both), because shorter form will be used also when not needed.
I'm assuming that there is no performance difference for BTFs. I see no reason to assume otherwise, but would be happy to be corrected.
An additional note on methodology: for the "applications" that I looked at (like Facebook and Netflix), I downloaded and concatenated the javascript found when loading a typical page. I'm assuming that the original code was written in javascript (as opposed to CoffeeScript or Java) and that minification did not significantly alter the resulting numbers.
These assumptions are significant, but since the outcome generally falls within the range found for open-source libraries, I'm fairly confident in the results. What strikes me is the similarity in usage patterns as opposed to the differences.
I'd be happy to run the tool against other libraries or applications, if there are suggestions.
On Tue, Mar 13, 2012 at 8:15 AM, Jason Orendorff <jason.orendorff at gmail.com> wrote:
Kevin Smith wrote:
For the surveyed code, the percentage of function expressions which do not reference "this" ranges between 31% and 87%. About half of all function expressions are suitable for conversion to BTFs. Clearly BTFs would offer immediate quantifiable benefit.
I'm confused by this paragraph. Functions that benefit from 'this' binding would reference 'this' or an alias for 'this' right?
...
This is great data to have.
Something I found really interesting about this is that if you delete Facebook and Netflix, this number goes up to 27%. In the MooTools code, it's 40%. So either it just varies wildly depending on programming style, or else library code has a greater need for "expression functions" than application code.
Everyone has to deal with the this-binding problem; every project will have some strategy. So a better analysis would start by determining the strategy for each project, then using the counting analysis to determine the ratio of functions needing this-binding based on the strategy. I think you will come up with a much higher number.
Some of the this-binding strategies I know about: var self = this; // usually 'self' but certainly 'this' alone on ther RHS Prototype bind www.prototypejs.org/api/function/bind local library bind/bindFixed (eg Firebug source) function() {}.bind(this); // modern code
jjb
I'm confused by this paragraph. Functions that benefit from 'this' binding would reference 'this' or an alias for 'this' right?
In this analysis, functions that reference an "alias" to this (e.g. var self = this) within an inner scope are counted:
(function() {
var self = this;
(function() { console.log(self); });
});
This results in 1 BTF candidate (the inner function).
In my analysis, I mention that this methodology will tend to undercount the BTF candidates, because functions with explicitly bound "this" (through Function.prototype.bind or other means) will tend to get marked as "methods":
element.onclick = function() {
console.log(this);
}.bind(this);
The analyzer reports 0 BTF candidates, even though we clearly should have
- Since the tool undercounts, we can say that the reported numbers offer a lower bound on BTF candidacy. The fact that BFT candidacy may be higher doesn't alter the analysis.
On Tue, Mar 13, 2012 at 9:25 AM, Kevin Smith <khs4473 at gmail.com> wrote:
I'm confused by this paragraph. Functions that benefit from 'this' binding would reference 'this' or an alias for 'this' right?
In this analysis, functions that reference an "alias" to this (e.g. var self = this) within an inner scope are counted:
(function() { var self = this; (function() { console.log(self); }); });
This results in 1 BTF candidate (the inner function).
Then does it count this: (function() { var self = this; (function() { console.log("foo"); }); }); ?
Can you answer the 'cost' side of the BTF issue? That is if BTF was really easy, how many times would we have to opt-out so we can use the default value of "this"? My guess: you will need a lot zeros in place of X in 0.0X% ;-)
Sometimes the 'this' is not needed at all; does it ever matter that it is set to the lexical this?
In my analysis, I mention that this methodology will tend to undercount the BTF candidates, because functions with explicitly bound "this" (through Function.prototype.bind or other means) will tend to get marked as "methods":
element.onclick = function() { console.log(this); }.bind(this);
Well FWIW I stop using "var self" the day bind() landed.
jjb
(function() { var self = this; (function() { console.log(self); }); });
- As stated above, it's assumed that BTFs will be preferred for clarity or brevity gains, even if bound-this is not required. "Opting out" of BTFs is no different than using classic functions, so I can't see that there is any cost involved.
Can you answer the 'cost' side of the BTF issue? That is if BTF was really easy, how many times would we have to opt-out so we can use the default value of "this"? My guess: you will need a lot zeros in place of X in 0.0X% ;-)
Sometimes the 'this' is not needed at all; does it ever matter that it is set to the lexical this?
There is a really big use case here that I worry about with BTF: jQuery event handlers
For whatever reason, the jQuery guys decided that it would be awesome if inside the handler, 'this' was bound to the dom element that the event handler was attached to.
$('#foo').bind('click', function() { alert($(this).text()); });
I think you'll find that pattern all over the place for those using jQuery.
On Tue, Mar 13, 2012 at 11:09 AM, John J Barton <johnjbarton at johnjbarton.com> wrote:
Everyone has to deal with the this-binding problem; every project will have some strategy. So a better analysis would start by determining the strategy for each project, then using the counting analysis to determine the ratio of functions needing this-binding based on the strategy. I think you will come up with a much higher number.
Kevin, do you have time to attempt this? I agree this is what you really want to measure, but contrary to jjb, I expect the number to be much lower!
That would be suitable for conversion to a BTF, perhaps like this (depending on syntax, of course):
$('#foo').bind('click', evt => { alert($(evt.target).text()) });
Again, this will be a case of the tool potentially undercounting BTF candidates.
Kevin, do you have time to attempt this?
Short answer: no. : )
I think the previous analysis is undercounting potential "expression functions". Consider the following case:
IO.File.readText(path, text => { console.log(text) });
Since we don't care what the callback returns, we could potentially rewrite it as an "expression function":
IO.File.readText(path, text => console.log(text));
I've rerun the analysis, creating another category for these single statement functions (spreadsheetdocs.google.com/spreadsheet/ccc?key=0Aro5yQ2fa01xdEJySWxhZ1VoZ0VaWTdldXp4NUtJd3c#gid=0). If we include this extra category, then about half of the BTF candidates may be suitable for rewriting as "expression functions" (depending on whether the return value is significant in context).
This suggests that multi-statement and expression-type BTFs should be given about equal priority with regard to syntax.
On Tue, Mar 13, 2012 at 9:47 AM, Kevin Smith <khs4473 at gmail.com> wrote:
Hi John,
(function() { var self = this; (function() { console.log(self); }); });
- As stated above, it's assumed that BTFs will be preferred for clarity or brevity gains, even if bound-this is not required. "Opting out" of BTFs is no different than using classic functions, so I can't see that there is any cost involved.
The cost comes from using BTF in cases where it will give erroneous results. If BTF exists, the next generation of JS developers will 'never' use grand-dad's function syntax. They will consider that form obscure and confusing. They won't recognize the cases where the old form is needed. So they will pay a cost to opt out of BTF.
If any! All (non-member) function expressions are either:
- OO and want lexical 'this',
- functional and don't care about 'this',
- Want default 'this' My claim is that category 1 > category 2 >>> category 3. Only
category 3 incurs this cost I outline.
jjb
On Tue, Mar 13, 2012 at 1:00 PM, Russell Leggett <russell.leggett at gmail.com>wrote:
Can you answer the 'cost' side of the BTF issue? That is if BTF was really easy, how many times would we have to opt-out so we can use the default value of "this"? My guess: you will need a lot zeros in place of X in 0.0X% ;-)
Sometimes the 'this' is not needed at all; does it ever matter that it is set to the lexical this?
There is a really big use case here that I worry about with BTF: jQuery event handlers
For whatever reason, the jQuery guys decided that it would be awesome if inside the handler, 'this' was bound to the dom element that the event handler was attached to.
Yes! Much like the DOM:
I've updated the tool to also analyze the number of formal parameters for each BTF candidate. I've haven't had time to update the spreadsheet, but for every body of code that I've sampled so far, 1 is the most common number of formal parameters.
This suggests that optimizing syntax for BTFs with one parameter might be worthwhile.
Kevin,
Over the weekend I applied David Herman's new tri-lambda syntax to Popcorn.js to see how it would look and feel:
rwldrn/popcorn-js/compare/tri-lambda
So, just now I ran Popcorn.js through your Analytics Machine, here is the output:
Total Function Expressions*: 63 65.625% Expression Functions**: 1219.047619047619047%Expression Functions That Return an Object Literal:00%Functions with a single statement:914.285714285714285%Block Functions:4266.66666666666666%
- Does not include function expressions that contain references to 'this' in its immediate scope.
** Function expressions whose first statement is a return. Parameter List Length 0 17.46031746031746% 1 47.61904761904761% 230.158730158730158%34.761904761904762%4 or more0%
Infix arrows are really nice looking aren't they? : )
Function expressions in object literals that could use concise method syntax?
On Mar 13, 2012, at 8:49 PM, Rick Waldron <waldron.rick at gmail.com> wrote:
On Tue, Mar 13, 2012 at 1:00 PM, Russell Leggett <russell.leggett at gmail.com> wrote:
Can you answer the 'cost' side of the BTF issue? That is if BTF was really easy, how many times would we have to opt-out so we can use the default value of "this"? My guess: you will need a lot zeros in place of X in 0.0X% ;-)
Sometimes the 'this' is not needed at all; does it ever matter that it is set to the lexical this?
There is a really big use case here that I worry about with BTF: jQuery event handlers
For whatever reason, the jQuery guys decided that it would be awesome if inside the handler, 'this' was bound to the dom element that the event handler was attached to.
Yes! Much like the DOM:
Hah! Shows how long it's been since I've actually written event code directly against the DOM. Still, that only makes for a stronger use case.
I've updated the tool to count the number of potential object literal methods as well. I'll post details tomorrow.
Rick Waldron wrote:
Over the weekend I applied David Herman's new tri-lambda syntax to Popcorn.js to see how it would look and feel:
Hi Rick, just FYI,
-
global.Popcorn[ methods.shift() ] = () => void 0;
could be written
-
global.Popcorn[ methods.shift() ] ==>;
as in CoffeeScript, per strawman:arrow_function_syntax (which I will revise tomorrow to reflect tri-lambdas).
Brendan Eich wrote:
global.Popcorn[ methods.shift() ] ==>;
Urgh, Postbox lied about a space.Should be:
global.Popcorn[ methods.shift() ] = ->;
Note single arrow.
Rick Waldron wrote:
Kevin,
Over the weekend I applied David Herman's new tri-lambda syntax to Popcorn.js to see how it would look and feel:
Why didn't you also apply 'method' syntax in 'name: () -> { ... }'
scenarios, it will probably be used in this cases rather then manually putting the function there (even in shorter syntax)?
It should not be forgotten then functions per se will only be used in the places where they are not methods put into class / object literal.
I have tried the tool with node-dom (Ayms/node-dom) to check what it would give on a whole site, not only a framework, see the result below for a usual web site (here www.castorama.fr), I did not compile it yet because it seems that there is a slight problem with the tool :
(function() {}) or (function(){var a=2}) etc ...
returns a BTF candidate...
I discovered it checking www.castorama.fr/homepage/homepage_20120227_full_anim.js which returns 21 BTF (because I was surprised by the result, since these sites are using frameworks we should not expect a lot of BTF functions outside)
As far as I have understood "Total Function Expressions" is supposed to return all functions that do not contain "this" in their initial scope and that have a "var self=this" trick that is used somewhere inside the function (ie function() {var self=this;var b=function() {console.log('test')} is not a BTF candidate because self is not used), correct ?
---------- script inline Total Function Expressions*:0 0.00% of 0 Expression Functions**:0 0.00% Expression Functions That Return an Object Literal:0 0.00% Functions with a single statement: 0 0.00% Block Functions:0 0.00% ---------- script www.castorama.fr/store/js/jquery.js Total Function Expressions*:417 52.85% of 789 Expression Functions**:132 31.65% Expression Functions That Return an Object Literal:2 0.48% Functions with a single statement: 95 22.78% Block Functions:190 45.56% ---------- script www.castorama.fr/store/js/main.js Total Function Expressions*:49 72.06% of 68 Expression Functions**:1 2.04% Expression Functions That Return an Object Literal:0 0.00% Functions with a single statement: 26 53.06% Block Functions:22 44.90% ---------- script inline Total Function Expressions*:4 100.00% of 4 Expression Functions**:0 0.00% Expression Functions That Return an Object Literal:0 0.00% Functions with a single statement: 3 75.00% Block Functions:1 25.00% ---------- script inline Total Function Expressions*:0 0.00% of 0 Expression Functions**:0 0.00% Expression Functions That Return an Object Literal:0 0.00% Functions with a single statement: 0 0.00% Block Functions:0 0.00% ---------- script www.castorama.fr/store/js/jquery.js Total Function Expressions*:417 52.85% of 789 Expression Functions**:132 31.65% Expression Functions That Return an Object Literal:2 0.48% Functions with a single statement: 95 22.78% Block Functions:190 45.56% ---------- script www.castorama.fr/homepage/homepage_20120227_full_anim.js Total Function Expressions*:21 100.00% of 21 Expression Functions**:0 0.00% Expression Functions That Return an Object Literal:0 0.00% Functions with a single statement: 17 80.95% Block Functions:4 19.05% ---------- script www.castorama.fr/homepage/homepage_20120227_full_menu.js Total Function Expressions*:1 50.00% of 2 Expression Functions**:0 0.00% Expression Functions That Return an Object Literal:0 0.00% Functions with a single statement: 1 100.00% Block Functions:0 0.00% ---------- script www.castorama.fr/js/jquery.cookie.js Total Function Expressions*:1 100.00% of 1 Expression Functions**:0 0.00% Expression Functions That Return an Object Literal:0 0.00% Functions with a single statement: 1 100.00% Block Functions:0 0.00% ---------- script inline Total Function Expressions*:0 0.00% of 0 Expression Functions**:0 0.00% Expression Functions That Return an Object Literal:0 0.00% Functions with a single statement: 0 0.00% Block Functions:0 0.00% ---------- script inline Total Function Expressions*:0 0.00% of 0 Expression Functions**:0 0.00% Expression Functions That Return an Object Literal:0 0.00% Functions with a single statement: 0 0.00% Block Functions:0 0.00% ---------- script inline Total Function Expressions*:0 0.00% of 0 Expression Functions**:0 0.00% Expression Functions That Return an Object Literal:0 0.00% Functions with a single statement: 0 0.00% Block Functions:0 0.00% ---------- script www.castorama.fr/js/s_code.js Total Function Expressions*:6 60.00% of 10 Expression Functions**:0 0.00% Expression Functions That Return an Object Literal:0 0.00% Functions with a single statement: 2 33.33% Block Functions:4 66.67% ---------- script inline Total Function Expressions*:0 0.00% of 0 Expression Functions**:0 0.00% Expression Functions That Return an Object Literal:0 0.00% Functions with a single statement: 0 0.00% Block Functions:0 0.00% ---------- script inline Total Function Expressions*:0 0.00% of 0 Expression Functions**:0 0.00% Expression Functions That Return an Object Literal:0 0.00% Functions with a single statement: 0 0.00% Block Functions:0 0.00% ---------- script inline Total Function Expressions*:0 0.00% of 0 Expression Functions**:0 0.00% Expression Functions That Return an Object Literal:0 0.00% Functions with a single statement: 0 0.00% Block Functions:0 0.00% ---------- script www.castorama.fr/js/tc_Castoramafr_1_load.js Total Function Expressions*:0 0.00% of 0 Expression Functions**:0 0.00% Expression Functions That Return an Object Literal:0 0.00% Functions with a single statement: 0 0.00% Block Functions:0 0.00% ---------- script www.castorama.fr/js/tc_Castoramafr_1_exec.js Total Function Expressions*:0 0.00% of 0 Expression Functions**:0 0.00% Expression Functions That Return an Object Literal:0 0.00% Functions with a single statement: 0 0.00% Block Functions:0 0.00% ---------- script ssl.google-analytics.com/urchin.js Total Function Expressions*:6 100.00% of 6 Expression Functions**:0 0.00% Expression Functions That Return an Object Literal:0 0.00% Functions with a single statement: 6 100.00% Block Functions:0 0.00% ---------- script inline Total Function Expressions*:0 0.00% of 0 Expression Functions**:0 0.00% Expression Functions That Return an Object Literal:0 0.00% Functions with a single statement: 0 0.00% Block Functions:0 0.00% Document complete ---------- script inline Total Function Expressions*:0 0.00% of 0 Expression Functions**:0 0.00% Expression Functions That Return an Object Literal:0 0.00% Functions with a single statement: 0 0.00% Block Functions:0 0.00% ---------- script inline Total Function Expressions*:0 0.00% of 0 Expression Functions**:0 0.00% Expression Functions That Return an Object Literal:0 0.00% Functions with a single statement: 0 0.00% Block Functions:0 0.00%
Le 14/03/2012 05:03, Kevin Smith a écrit :
As far as I have understood "Total Function Expressions" is supposed to return all functions that do not contain "this" in their initial scope and that have a "var self=this" trick that is used somewhere inside the function (ie function() {var self=this;var b=function() {console.log('test')} is not a BTF candidate because self is not used), correct ?
Sorry, no. As stated previously, I'm assuming for the purposes of this analysis that BTFs will be used in cases where (a) we want lexical "this" and (b) we don't care about "this" at all. Why in the second case? Because BTF syntax will be more concise and will generally express the intent better.
When I started this research, I wasn't aware of the "tri-lambda" work being done, and specifically the proposal that there be two short function syntaxes: one for classic functions (->) and one for bound this (=>). Clearly some of the BTF candidates could go either way, and we really can't make that distinction in this analysis.
I've updated the spreadsheetdocs.google.com/spreadsheet/ccc?key=0Aro5yQ2fa01xdEJySWxhZ1VoZ0VaWTdldXp4NUtJd3cto
show a count of "object literal methods" for each sampled code base. These are function expressions which are the values in an object literal, and that reference "this" somewhere in their immediate scope. Note that there is no overlap between this category and the BTF category.
Interestingly, when we take the sum of BTF candidates and object literal methods, we account for over 90% of function expressions. This suggests that an additional short function syntax that does not bind 'this' may not be necessary.
On Mar 14, 2012, at 4:17 AM, Herby Vojčík <herby at mailbox.sk> wrote:
Rick Waldron wrote:
Kevin,
Over the weekend I applied David Herman's new tri-lambda syntax to Popcorn.js to see how it would look and feel:
Why didn't you also apply 'method' syntax in 'name: () -> { ... }' scenarios, it will probably be used in this cases rather then manually putting the function there (even in shorter syntax)?
Pretty sure I did - did I miss some?
Rick Waldron wrote:
On Mar 14, 2012, at 4:17 AM, Herby Vojčík<herby at mailbox.sk> wrote:
Rick Waldron wrote:
Kevin,
Over the weekend I applied David Herman's new tri-lambda syntax to Popcorn.js to see how it would look and feel:
rwldrn/popcorn-js/compare/tri-lambda Why didn't you also apply 'method' syntax in 'name: () -> { ... }' scenarios, it will probably be used in this cases rather then manuallyputting the function there (even in shorter syntax)?
I meant here, use allen's method syntax instead of () -> { ... }
Pretty sure I did - did I miss some?
Lots, like
error: ( msg ) -> { throw new Error( msg ); }
which should be
error (msg) { throw new Error( msg ); }
On Wed, Mar 14, 2012 at 9:26 AM, Herby Vojčík <herby at mailbox.sk> wrote:
Rick Waldron wrote:
On Mar 14, 2012, at 4:17 AM, Herby Vojčík<herby at mailbox.sk> wrote:
Rick Waldron wrote:
Kevin,
Over the weekend I applied David Herman's new tri-lambda syntax to Popcorn.js to see how it would look and feel:
rwldrn/**popcorn-js/compare/tri-lambdarwldrn/popcorn-js/compare/tri-lambda
Why didn't you also apply 'method' syntax in 'name: () -> { ... }' scenarios, it will probably be used in this cases rather then manuallyputting the function there (even in shorter syntax)?
I meant here, use allen's method syntax instead of () -> { ... }
Pretty sure I did - did I miss some?
Lots, like
error: ( msg ) -> { throw new Error( msg ); }
which should be
error (msg) { throw new Error( msg );
}
Oh, right, gotcha - because I was following the "tri-lambda" concept that David Herman posted here: gist.github.com/2011902
If I have time today, I will write an alternate version with Allen's syntax
Kevin Smith wrote:
This suggests that an additional short function syntax that does not bind 'this' may not be necessary.
This is helpful.
Still I am in favor of (params) -> {stmts} as shorthand for unbound-this
function, assuming (params) => assign-expr makes it. There are enough
use-cases, even at ~10%, to make the case. We don't add affordances only for the 80% or even 90% cohort. Expert cohorts and the tyranny of JS's statement vs. expression grammar inherited from C, combined with plain old function being overlong, suggest at least considering -> functions.
Adding do expressions to the mix, TCP conformant in all ways, does undermine my minority-use-case argument, though. (params) => do {stmts}
has a bit too much in the middle (=>do) and the TCP-ness means
plain-old-function use-cases need careful rewriting and may suffer high binding overhead, but if those are rare enough...
The method definition shorthand for plain-old-functions as property initialisers undermines the case for -> too.
I still intend to update the arrow function syntax strawman to include thin arrow but it will be something that could be cut without hurting => (and I'll link to the do-expressions strawman).
On Mar 13, 2012, at 6:20 PM, Rick Waldron wrote:
Kevin,
Over the weekend I applied David Herman's new tri-lambda syntax to Popcorn.js to see how it would look and feel:
So when I scan the diffs and my eye pass over pairs of changes like:
-(function(global, document) { +((global, document) -> {
or
-
var DOMContentLoaded = function() {
-
let DOMContentLoaded = () -> {
or
- Popcorn.p[ api ] = function() {
- Popcorn.p[ api ] = () -> {
or
- script.addEventListener( "load", function() {
- script.addEventListener( "load", () -> {
my eyes invariably go to the first line of each pair and I have a minor mental WTF moment when I look at the second line. Now some of this is no doubt a matter of familiarity, but does anyone really think that the second forms are more readable even with experience. At least in western cultures, are brains are trained from a early age to recognize meaning in words. Symbols are far less common and symbol semantically meaningful symbol sequences are even rarer.
In what way does this syntax help people read and understand code?
So BTF stands for "bound-this function expressions"
But it does include case b (don't care about "this")
Then in the next email you conclude :
"Interestingly, when we take the sum of BTF candidates and object literal methods, we account for over 90% of function expressions."
Is it surprising ?
"This suggests that an additional short function syntax that does not bind 'this' may not be necessary."
??? Why ? Because except object literal methods (+/-50% for which the lexical this is not supposed to be needed) most of the functions are the b case ?
I should be missing something important... don't understand exactly what the analysis does highlight, thanks if you can give more details
Le 14/03/2012 13:46, Kevin Smith a écrit :
On Wed, Mar 14, 2012 at 4:53 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:
On Mar 13, 2012, at 6:20 PM, Rick Waldron wrote:
Kevin,
Over the weekend I applied David Herman's new tri-lambda syntax to Popcorn.js to see how it would look and feel:
rwldrn/popcorn-js/compare/tri-lambda ...
So when I scan the diffs and my eye pass over pairs of changes like:
-(function(global, document) {
+((global, document) -> {
or
var DOMContentLoaded = function() {
let DOMContentLoaded = () -> {
or
- Popcorn.p[ api ] = function() {
- Popcorn.p[ api ] = () -> {
or
- script.addEventListener( "load", function() {
- script.addEventListener( "load", () -> {
my eyes invariably go to the first line of each pair and I have a minor mental WTF moment when I look at the second line. Now some of this is no doubt a matter of familiarity, but does anyone really think that the second forms are more readable even with experience. At least in western cultures, are brains are trained from a early age to recognize meaning in words. Symbols are far less common and symbol semantically meaningful symbol sequences are even rarer.
By the time I was about a quarter of the way through making these changes, the "function() {..." starting looking and feeling like the syntax that was out of place. My instinct was to "seek and destroy", replacing them with the much simpler syntax and it felt satisfying and enjoyable to do so.
Technical and grammatical point aside, I really enjoyed writing this code.
For me no. I have looked into popcorn.js today and could not convince myself that it was more readable, maybe it's a question of history or feelings (and to get used to it) but without being an expert in all languages, I consider js to be a unique (clever) language, using the arrow notation makes it look like others, this argument might look weak but for js or others I am not a fan of the arrow notation... will not make friends, I know
It is confusing right now whether the arrow proposal and do proposal are distinct/exclusive or not
I read about popcorn (--> Herby) :
error: ( msg ) -> { throw new Error( msg ); }
which should be
error (msg) { throw new Error( msg ); }
Where is this specified ? And what happens with get: function() {.....} or set ?
Le 14/03/2012 21:53, Allen Wirfs-Brock a écrit :
Forget this below, sorry I got confused, coming back to your first email your tool does count function expressions that do not have "this" in their immediate scope, so indeed functions that potentially need the literal "this", then you add object literal methods, then this leaves 10% function that can keep the old syntax or get a new shorter syntax that does not bind "this"
OK, then I have tried again the tool on an ajax app (www.blimpme.com/mobile), the total BTF candidates drops to 77.6 %
I think it is due to the fact that :
var x=document.createElement('div'); x.onmousedown=function() {var a=this.style};
var y=function() {var a=this;}; x.onmouseover=y;
are not counted as BTF candidates
Since I have not yet understood what should become methods with the arrow/do or do proposals, I can not say more...
Le 14/03/2012 22:15, Aymeric Vitte a écrit :
I'm glad we're on the same page. I analyzed the code from that site and got the same results as you. The percentage of BTF candidates is 68% of all function expressions, but the combined BTF candidates and object literal methods are only 78%.
There are very few object literal methods in this sample, so in order to explain the 78% we're going to have to dig into the "non-method" forms.
As you point out, event handlers are attached using the following idiom:
element.onevent = function() { ...this... };
Although they are not trivially convertible to BTFs, event handlers as above can generally be refactored like this (using a purely expository BTF syntax):
element.onevent = () => { ...element... };
or even:
element.onevent = (evt) => { ...evt.target... };
I think think analysis supports the idea that BTFs are widely applicable.
I think I have missed something in the discussions (or globally) because I don't understand very well why methods are involved in lexical this.
But if it is so, why events handlers should be different from a js perspective ? Maybe you could include in the tool everything that is a method function expression
Probably it will be more clear once the proposals are updated (or maybe I read it in a wrong way but I don't see what happens to methods), and the example below illustrated (I have tried to write what it will become, probably completely wrong) :
-------------------- Today
var a=function() {var self=this;var c=function() {var a=self;return a}}; var test='essai'; var o={test: 'test'}; o.m = function() {var a=this.test;return a} a = o.m; var b=function() {}; b.prototype={ test2: function() {var a=this;return a} } o.m(); //test a(); //essai
--------------------- Tomorrow
var a=function() {var c=() => this}; (fat arrow)
or var a=fn() {var c=() => do {var a=this;return a}; (fn + fat arrow)
or var a=fn() {var c= do () this}; (do) or var a=fn() {var c= do () {var a=this;return a}}; (do)
b.prototype={ test2: () => this } or ... same as above or b.prototype={ test2() {var a=this;return this} }
o.m = () => this;
or o.m =() => do {var a=this.test;return a};
or o.m = do () this; or o.m = do () {var a=this.test;return a}; a=o.m;
o.m();//essai ??? a();//essai ???
Le 16/03/2012 14:44, Kevin Smith a écrit :
BTF is shorthand for "bound-this function expressions". BTFs are semantically equivalent to classic function expressions with the exception that "this" is lexically bound.
*Methodology *
Using a modified version of the ES parser in UglifyJS, I generated an AST for the input string. I then traverse the AST, counting all occurrences of function expressions which do not contain a reference to "this" in its immediate scope. Of those function expressions, I count the number of functions whose first statement is a return statement, and of those, how many return an object literal in that return statement.
The results so far can be viewed as a spreadsheetdocs.google.com/spreadsheet/ccc?key=0Aro5yQ2fa01xdENxUzBuNXczb21vUWVUX0tyVmNKTUE#gid=0 .
The tool used for this analysis is available at www.khs4473.com/function-expr-count.
*Analysis *
The total number of function expressions counted gives us a rough idea of how many function expressions could be converted to BTFs. In reality the number could be higher, since I'm not analyzing usage of Function.prototype.bind to achieve the same goal. For the surveyed code, the percentage of function expressions which do not reference "this" ranges between 31% and 87%. About half of all function expressions are suitable for conversion to BTFs. Clearly BTFs would offer immediate quantifiable benefit.
Of the surveyed code, about 19% of BTF candidates contain a return statement as their first statement. This suggests that BTF syntax should be optimized for both "expression functions" and multi-statement function bodies, but with a preference given to multi-statement functions.
Of the "expression functions", only 1.5% return an object literal. This suggests that BTF syntax should give preference to other forms, if there is a conflict.
Thanks,