arrow function syntax simplified

# Brendan Eich (8 years ago)

strawman:arrow_function_syntax

Use => only with an expression body (do-expressions if accepted allow

statements and combined with => compete with block-lambdas).

Use -> only with body block, as for long-form function.

I deferred other accretions.

In a rush here, comments and corrections welcome and I'll edit as I can.

# Axel Rauschmayer (8 years ago)

Looks good. Not sure if the different rules for the body aren’t confusing.

# Rick Waldron (8 years ago)

Yes, please. This looks and feels like the proposal from Dave Herman that I supported (and enjoyed writing examples for) the most.

Very exciting to see this moving along and finding wider support.

# Luke Hoban (8 years ago)

Great to see the arrow syntax proposal moving forward.

I think I missed a step though in the reasoning for moving to this proposal vs. the previous arrow proposal. What problem did the previous proposal have that is addressed with the new proposal?

There's a couple concerns I have with complexity added in the new version of this proposal:

  1. => and -> look similar, but have multiple points of difference. Both what is allowed on the RHS and also binding of 'this'. That will likely make this harder to explain and harder to reason about code on quick inspection.

  2. This version seems to more or less rely on 'do expressions' to make the => form fully usable, which are more of a departure from current JS than arrow syntax itself. What was the reason to disallow statement bodies on the RHS of =>?

Luke

# Russell Leggett (8 years ago)

On Tue, Mar 27, 2012 at 3:43 PM, Brendan Eich <brendan at mozilla.com> wrote:

**doku.php?id=strawman:arrow_**function_syntaxstrawman:arrow_function_syntax

Use => only with an expression body (do-expressions if accepted allow statements and combined with => compete with block-lambdas).

Use -> only with body block, as for long-form function.

Just a thought - if a block is required on the RHS of the ->, why not just

skip the arrow? I could be mistaken, but would it be just as easy grammatically to do:

array.forEach((v, i) { if (i & 1) oddArray[i >>> 1] = v; });

instead of:

 array.forEach((v, i) -> { if (i & 1) oddArray[i >>> 1] = v; });

This way, there would only be one kind of arrow. Without an arrow its basically just removing the keyword function, and therefore maybe a little bit easier to transition. With the arrow added, you can expect a bigger jump in semantics.

# Brendan Eich (8 years ago)

On Mar 27, 2012, at 5:08 PM, Luke Hoban <lukeh at microsoft.com> wrote:

Great to see the arrow syntax proposal moving forward.

I think I missed a step though in the reasoning for moving to this proposal vs. the previous arrow proposal. What problem did the previous proposal have that is addressed with the new proposal?

The ambiguity between a block body and an object literal expression body, which we would prefer to resolve in favor of object literal. The solutions considered before this edit were:

Both are hairy and not near consensus in TC39. The first isn't backward-compatible on edge cases that probably exist on the web. The second is future-hostile.

There's a couple concerns I have with complexity added in the new version of this proposal:

  1. => and -> look similar, but have multiple points of difference. Both what is allowed on the RHS and also binding of 'this'. That will likely make this harder to explain and harder to reason about code on quick inspection.

Early errors help, and users learn. There is even a "YAGNI" opinion that says => is all you need, and Kevin Smith actually wrote an analysis tool to measure incidence, which supports this view.

  1. This version seems to more or less rely on 'do expressions' to make the => form fully usable, which are more of a departure from current JS than arrow syntax itself. What was the reason to disallow statement bodies on the RHS of =>?

See above, block vs object literal. Restricting => to have only an expression body and -> to have only a block body is the simple, brute-force solution. "When in doubt, use brute force."

I think fully TCP- compliant do expressions are pure win, FTR.

# Brendan Eich (8 years ago)

We went over this in the thread Isaac started. You'd need a [no LineTerminator here] between ) and {, and then the syntax looks too much like a juxtaposed parenthesized expression and block.

The latter problem, a lack of syntactic distinctiveness, also felled there entry mooted {(x)x} block-lambda alternative syntax.

# Rick Waldron (8 years ago)

[snip]

I think fully TCP- compliant do expressions are pure win, FTR.

I second this, of course, based solely on the experience I had writing up these examples:

gist.github.com/2013909

rwldrn/popcorn-js/compare/tri-lambda

rwldrn/popcorn-js/blob/481338a3ab05ad3423c67b70df690bf19977f9bc/popcorn.js

# Brendan Eich (8 years ago)

On Mar 27, 2012, at 5:28 PM, Brendan Eich <brendan at mozilla.com> wrote:

We went over this in the thread Isaac started. You'd need a [no LineTerminator here] between ) and {, and then the syntax looks too much like a juxtaposed parenthesized expression and block.

The latter problem, a lack of syntactic distinctiveness, also felled there entry

Thanks, iPad!

"the recently mooted", of course.

# Russell Leggett (8 years ago)

On Tue, Mar 27, 2012 at 5:28 PM, Brendan Eich <brendan at mozilla.com> wrote:

We went over this in the thread Isaac started. You'd need a [no LineTerminator here] between ) and {, and then the syntax looks too much like a juxtaposed parenthesized expression and block.

The latter problem, a lack of syntactic distinctiveness, also felled there entry mooted {(x)x} block-lambda alternative syntax.

Makes sense. I think the required block in one and the required lack of block in the other should be enough for distinguishing the two. I can get behind this. The => does combine nicely with do expression, and hits a

sweet spot on its own.

# Luke Hoban (8 years ago)

I think fully TCP- compliant do expressions are pure win, FTR.

I second this, of course, based solely on the experience I had writing up these examples:

gist.github.com/2013909

rwldrn/popcorn-js/compare/tri-lambda

rwldrn/popcorn-js/blob/481338a3ab05ad3423c67b70df690bf19977f9bc/popcorn.js

Rick

Looking through those examples, I don't  see any cases where TCP-compliant do expressions are actually needed. In the original arrow proposal, I believe all the code would be the same, except 10 or so occurrences of "=> do" would become just "=>". These examples seem to support the simpler approach of the original arrow proposal.

Note that the => is what provides lexical this binding in the body. The do expressions serve a separate purpose of changing the meaning of return (but not break and continue), and allowing use of completion results as returns (which tends to look a bit awkward in curly brace languages, and I don't believe was used in any of the examples linked above though it's hard to tell for sure due to completion value leak).

Luke

# Luke Hoban (8 years ago)

Great to see the arrow syntax proposal moving forward.

I think I missed a step though in the reasoning for moving to this proposal vs. the previous arrow proposal. What problem did the previous proposal have that is addressed with the new proposal? The ambiguity between a block body and an object literal expression body, which we would prefer to resolve in favor of object literal. The solutions considered before this edit were:

Got it. I understood that ambiguity to be fully addressed by the two-token lookahead proposal that was detailed in the wiki.

The future hostility concern doesn't seem so serious as to kill this proposal - especially relative to the value of simple short function syntax. The future hostility would only seem to come in if we introduced new object literal syntax which was truly ambiguous with blocks. My understanding is that that is very unlikely, and not the primary future hostility concern - is that right? If the new syntax does not have true ambiguities, it can be addressed in the future by expanding lookahead if needed. Perhaps there is a concrete syntactic extension that has caused concern?

Alternatively - resolving the ambiguity in favor of the block body feels acceptable if it keeps the proposal simple in other key ways. As you noted, except in the {} case, this will produce early errors that point to the solution.

Luke

# Brendan Eich (8 years ago)

Luke Hoban wrote:

The do expressions serve a separate purpose of changing the meaning of return (but not break and continue)

Dave proposed at

esdiscuss/2012-March/021000

that do expressions be fully TCP compliant. No way to be half-pregnant :-/.

# Luke Hoban (8 years ago)

Luke Hoban wrote: The do expressions serve a separate purpose of changing the meaning of return (but not break and continue) Dave proposed at esdiscuss/2012-March/021000 that do expressions be fully TCP compliant. No way to be half-pregnant :-/.

True - I misspoke there. The concern related to break and continue I had in mind was separate from what I noted - it is the issues raised at esdiscuss/2012-January/019525.

But my primary point was just that in Rick's examples, there doesn't appear to be any reliance on TCP at all. Had => supported blocks on the RHS as in the original arrow proposal, all the code samples would be simpler, simply removing the 'do'. I believe this will generally be true too.

Luke

# Brendan Eich (8 years ago)

Luke Hoban wrote:

The future hostility concern doesn't seem so serious as to kill this proposal - especially relative to the value of simple short function syntax. The future hostility would only seem to come in if we introduced new object literal syntax which was truly ambiguous with blocks.

That was proposed for ES6, and while the particular proposal was withdrawn (the ~, !, and other prefixes on property names in object literals), the general issue is freedom in the future to extend object literal syntax in a way that is ambiguous with block syntax.

Right now, because a { at start of statement must be the start of a block, there's no new hardship and only the long-standing (ES3 era) one-token lookahead restriction.

Adding new restrictions, IIRC, did not fare well last year at a TC39 meeting. I can't find a record in the notes about this other than

esdiscuss/2011-May/014758

Cc'ing Waldemar.

My understanding is that that is very unlikely, and not the primary future hostility concern - is that right?

I think it's the only hostility concern.

If the new syntax does not have true ambiguities, it can be addressed in the future by expanding lookahead if needed. Perhaps there is a concrete syntactic extension that has caused concern?

Adding lookahead is risky because of ASI and regular expression vs. division "/" modality. I haven't worked through all the issues myself, and that is one reason I simplified arrow function syntax today.

Alternatively - resolving the ambiguity in favor of the block body feels acceptable if it keeps the proposal simple in other key ways.

TC39 members rejected this approach. An expression-bodied short function should admit the entire expression being an object literal, no extra parentheses required. Doug was quite outspoken on this point.

# Rick Waldron (8 years ago)

On Tue, Mar 27, 2012 at 7:46 PM, Luke Hoban <lukeh at microsoft.com> wrote:

Luke Hoban wrote: The do expressions serve a separate purpose of changing the meaning of return (but not break and continue) Dave proposed at esdiscuss/2012-March/021000 that do expressions be fully TCP compliant. No way to be half-pregnant :-/.

True - I misspoke there. The concern related to break and continue I had in mind was separate from what I noted - it is the issues raised at esdiscuss/2012-January/019525.

But my primary point was just that in Rick's examples, there doesn't appear to be any reliance on TCP at all. Had => supported blocks on the RHS as in the original arrow proposal, all the code samples would be simpler, simply removing the 'do'. I believe this will generally be true too.

All of the cases that use () => do { } are doing so where they require

multiple statement expressions that inherit lexical |this|.

Unless I've missed something, the examples are correct.

IINM, these meet the TCP use case:

rwldrn/popcorn-js/blob/481338a3ab05ad3423c67b70df690bf19977f9bc/popcorn.js#L15, rwldrn/popcorn-js/blob/481338a3ab05ad3423c67b70df690bf19977f9bc/popcorn.js#L282, rwldrn/popcorn-js/blob/481338a3ab05ad3423c67b70df690bf19977f9bc/popcorn.js#L481, rwldrn/popcorn-js/blob/481338a3ab05ad3423c67b70df690bf19977f9bc/popcorn.js#L487

# Kevin Smith (8 years ago)

I like the => syntax, but I'm not convinced regarding single arrow

functions.

Some observations:

  1. A shorter function syntax for classic functions doesn't seem to carry much payoff.

  2. Generally, users will want closures to have lexically-bound this. The strawman makes this possible via either do expressions ("=> do") or this

initializers ("(this=this, ...) -> {}"), both of which are somewhat "clunky". This would seem to make a large portion (perhaps even a slight majority) of candidates for this syntax pay a "clunk" tax.

This would seem to indicate that -> functions should have lexically-bound

this.

Also, in my analysis, I discovered that the most common number of formal parameters for arrow function candidates is one. I think that readability can be improved if we can eliminate parenthesis for this common case, as in C#.

array.map((x) => x * x);
// vs.
array.map(x => x * x);
# Luke Hoban (8 years ago)

But my primary point was just that in Rick's examples, there doesn't appear to be any reliance on TCP at all.  Had => supported blocks on the RHS as in the original arrow proposal, all the code samples would be simpler, simply removing the 'do'.  I believe this will generally be true too.

All of the cases that use () => do { } are doing so where they require multiple statement expressions that inherit lexical |this|.

Right. In the original arrow syntax [1] proposal "() => { this.foo(); }" gave lexical this with a statement body, which covers the use cases I saw in the examples you shared. The point I was trying to make here is that lexical this is a separate issue from TCP. If we deem it important to address lexical this with a different variant of arrow, we can do that without needing to add TCP preserving blocks. These can be separate concerns.

I actually think it's worth starting simple here (maximal minimalism again). There is a lot of value in just having shorthand for exactly what 'function' is used for today. Only statement bodies, no lexical this, nothing fancy for nullary parameter lists. That alone would be a huge win, and would add effectively no additional complexity/concept count.

Luke

[1] doku.php?id=strawman:arrow_function_syntax&rev=1307297899

# Brendan Eich (8 years ago)

Luke Hoban wrote:

I actually think it's worth starting simple here (maximal minimalism again). There is a lot of value in just having shorthand for exactly what 'function' is used fortoday. Only statement bodies, no lexical this, nothing fancy for nullary parameter lists. That alone would be a huge win, and would add effectively no additional complexity/concept count.

Kevin's analysis contradicts your assertion. Expression-bodied functions with bound |this| (or var self=this outside) predominate in the code he surveyed.

# Brendan Eich (8 years ago)

Kevin Smith wrote:

I like the => syntax, but I'm not convinced regarding single arrow functions.

Me neither.

Some observations:

  1. A shorter function syntax for classic functions doesn't seem to carry much payoff.

Only six letters.

  1. Generally, users will want closures to have lexically-bound this. The strawman makes this possible via either do expressions ("=> do") or this initializers ("(this=this, ...) -> {}"), both of which are somewhat "clunky".

No, the strawman says => always lexically binds |this|. How was it

unclear? I will fix it.

I'm going to cut the this=... jazz.

Also, in my analysis, I discovered that the most common number of formal parameters for arrow function candidates is one. I think that readability can be improved if we can eliminate parenthesis for this common case, as in C#.

array.map((x) => x * x);
// vs.
array.map(x => x * x);

We could do this, but only for the single identifier case.

# Brendan Eich (8 years ago)

Brendan Eich wrote:

Kevin's analysis contradicts your assertion. Expression-bodied functions with bound |this| (or var self=this outside) predominate in the code he surveyed.

See thread headed by this message:

esdiscuss/2012-March/021126

# Kevin Smith (8 years ago)

No, the strawman says => always lexically binds |this|. How was it unclear? I will fix it.

Yes - I understood that. My point (and I was probably being unclear - it's late here on the east coast) was that if you want lexically bound this for multistatement closures, you can choose

(x) => do { ;;; }

// or

(this = this, x) -> { ;;; }

Both of which are a little heavy. Not bad, though. On the other hand, this might strike just the right balance:

(x) -> {
  this; // lexically bound - yay!
}

In other words, all arrow functions would have lexically bound this, and the fatness of the arrow would distinguish between blocks and expressions. This is a departure from CoffeeScript, I realize.

# Brendan Eich (8 years ago)

But aren't non-BTFs rare based on your (revised and original) measurements?

# Kevin Smith (8 years ago)

But aren't non-BTFs rare based on your (revised and original) measurements?

When you take out the object literal methods, that's right.

The precise way to say it would be that ~90% of function expressions in the code I analyzed were either object literal methods or did not depend on dynamic |this|.

That's exactly the reason I'm suggesting lexically bound |this| for "->"

functions, because outside of "methods" (which already have shorter syntax, either via object literal extensions or classes), there doesn't appear to be a great need for function expressions with dynamic |this|.

# Brendan Eich (8 years ago)

Kevin Smith wrote:

That's exactly the reason I'm suggesting lexically bound |this| for "->" functions, because outside of "methods" (which already have shorter syntax, either via object literal extensions or classes), there doesn't appear to be a great need for function expressions with dynamic |this|.

We could indeed make -> bind |this| by fiat and take a block.

I hate the CoffeeScript deviation, though. It's just confusing for anyone who ever learned that fat-arrow binds |this| and thin-arrow doesn't.

If the use-case for block bodies with bound |this| is uncommon enough, we could just say "use a good ol' function expression long-hand." Would that be so bad, compared to the alternative you're suggesting?

# Rick Waldron (8 years ago)

On Tuesday, March 27, 2012 at 9:54 PM, Luke Hoban wrote:

But my primary point was just that in Rick's examples, there doesn't appear to be any reliance on TCP at all. Had => supported blocks on the RHS as in the original arrow proposal, all the code samples would be simpler, simply removing the 'do'. I believe this will generally be true too.

All of the cases that use () => do { } are doing so where they require multiple statement expressions that inherit lexical |this|.

Right. In the original arrow syntax [1] proposal "() => { this.foo(); }" gave lexical this with a statement body, which covers the use cases I saw in the examples you shared. The point I was trying to make here is that lexical this is a separate issue from TCP. If we deem it important to address lexical this with a different variant of arrow, we can do that without needing to add TCP preserving blocks. These can be separate concerns.

I actually think it's worth starting simple here (maximal minimalism again). There is a lot of value in just having shorthand for exactly what 'function' is used for today. Only statement bodies, no lexical this, nothing fancy for nullary parameter lists. That alone would be a huge win, and would add effectively no additional complexity/concept count.

Thanks for the clarification, always appreciated.

# Kevin Smith (8 years ago)

I hate the CoffeeScript deviation, though. It's just confusing for anyone who ever learned that fat-arrow binds |this| and thin-arrow doesn't.

True. On the other hand, "all arrows bind |this|" is also quite simple and easy to remember.

If the use-case for block bodies with bound |this| is uncommon enough, we

could just say "use a good ol' function expression long-hand." Would that be so bad, compared to the alternative you're suggesting?

I think that use case is quite common, if we include function expressions that don't care about |this|, bound or not. For Node's js source (as of a few weeks ago), there are 456 function expressions which are algorithmically convertible to bound |this| forms (because they either currently explicitly bind using self = this or because they don't care about |this|). Of those, about 60% are multi-statement.

As an example, the following function expression is multi-statement and since it doesn't care about |this|, it can be rewritten using a (shorter) bound |this| form:

joyent/node/blob/master/lib/http.js#L1633

# Russell Leggett (8 years ago)

On Mar 27, 2012, at 10:36 PM, Kevin Smith <khs4473 at gmail.com> wrote:

But aren't non-BTFs rare based on your (revised and original) measurements?

When you take out the object literal methods, that's right.

The precise way to say it would be that ~90% of function expressions in the code I analyzed were either object literal methods or did not depend on dynamic |this|.

That's exactly the reason I'm suggesting lexically bound |this| for "->" functions, because outside of "methods" (which already have shorter syntax, either via object literal extensions or classes), there doesn't appear to be a great need for function expressions with dynamic |this|.

I'm sure this is a bit of a tangent, but the other major related case is passing a "method" as an argument but needing to retain the correct "this". Obviously, that is what bind was meant for, but that is inconvenient when passing methods for the same reason it would be inconvenient for anonymous functions.

I guess what I'm proposing is a syntax supported version of bind that is independent of shorter function syntax entirely. Don't hold me to the syntax, because I don't think its right, its just to give you an idea.

//let say I have some object foo with a method bar that I want called as a callback
//right now I have to use bind, or wrap the call in an additional function
needsCallback(foo.bar.bind(foo);

//also happens inside the class itself, and you'll see
needsCallback(this.bar.bind(this));

//and finally, the case we're addressing now
needsCallback(function(x,y){
	if(x){
		this.doX(x);
	else{
		this.doY(y);
	}
}.bind(this));

What if we had a shorthand for bind that worked in both of these cases

//here the # acts as both a . and bind in one
needsCallback(foo#bar)
needsCallback(this#bar)

//in this case, it obviously doesn't access a property, it just does a bind
needsCallback(this#function(x,y){
	if(x){
		this.doX(x);
	else{
		this.doY(y);
	}
});
//or with the new syntax
needsCallback(this#(x,y)->{
	...
});

I'm guessing this idea is a stretch or possibly even suggested already and tossed out, but it came to me as a possibility and I thought I would mention it.

# Luke Hoban (8 years ago)

Brendan Eich wrote:

Kevin's analysis contradicts your assertion. Expression-bodied functions with bound |this| (or var self=this outside) predominate in the code he surveyed.

See thread headed by this message:

esdiscuss/2012-March/021126

Yeah - I followed the earlier discussion on the data Kevin gathered, which is great input. From the spreadsheet linked in Kevin's mail above, it looks like 81% of function expressions had statement bodies, and >50% did not reference this. While these were cast as BTF candidates, they are also just as much candidates for benefitting from no-frills function shorthand.

There are a couple of separate topics being tackled simultaneously here (1) 'function' is cumbersome (2) 'var self = this' is cumbersome (3) '{ return }' is cumbersome. We can separate concerns if we want, and solve only a subset of these problems. From Kevin's analysis - solving (1) helps 100% of function expressions, solving (2) helps 45% of function expressions and solving (3) helps 9% of function expressions. That's the basis of my claim that just solving (1) would be a big win.

Note: Kevin had a follow up where the % of functions with statement bodies was revised, using examples like 'text => { console.log(text) }'. Since these don't really hit the 'cumbersome' path in case (3) above, I'm quoting the original numbers which characterized where problem (3) was a current pain point.

Luke

# Herby Vojčík (8 years ago)

Kevin Smith wrote:

But aren't non-BTFs rare based on your (revised and original)
measurements?

When you take out the object literal methods, that's right.

The precise way to say it would be that ~90% of function expressions in the code I analyzed were either object literal methods or did not depend on dynamic |this|.

Data are data, if numbers show that it is probably true, but it seems strange to me, I always thought a big use case for dynamic this are the DOM events... didn't they use this pervasively (it was my impression $(this) is all over...).

# Claus Reinke (8 years ago)

The ambiguity between a block body and an object literal expression body, which we would prefer to resolve in favor of object literal. The solutions considered before this edit were:

Both are hairy and not near consensus in TC39. The first isn't backward- compatible on edge cases that probably exist on the web. The second is future-hostile.

An alternative suggestion was to default to object, but to use an empty statement prefix to get an unambiguous block {; ..}. Then, we'd have

  • statement context: default to block, use parens ({..}) to get object
  • expression context: default to object, use empty statement {;..} to get block

{; ..} might be a notation-alternative to do-expressions, saving a valuable keyword. This would require compatible completion-value semantics.

Claus

# John J Barton (8 years ago)

On Tue, Mar 27, 2012 at 9:39 PM, Luke Hoban <lukeh at microsoft.com> wrote:

Brendan Eich wrote:

Kevin's analysis contradicts your assertion. Expression-bodied functions with bound |this| (or var self=this outside) predominate in the code he surveyed.

See thread headed by this message:

esdiscuss/2012-March/021126

Yeah - I followed the earlier discussion on the data Kevin gathered, which is great input. From the spreadsheet linked in Kevin's mail above, it looks like 81% of function expressions had statement bodies, and >50% did not reference this. While these were cast as BTF candidates, they are also just as much candidates for benefitting from no-frills function shorthand.

There are a couple of separate topics being tackled simultaneously here (1) 'function' is cumbersome (2) 'var self = this' is cumbersome (3) '{ return }' is cumbersome. We can separate concerns if we want, and solve only a subset of these problems. From Kevin's analysis - solving (1) helps 100% of function expressions, solving (2) helps 45% of function expressions and solving (3) helps 9% of function expressions. That's the basis of my claim that just solving (1) would be a big win.

Your claim is based on assuming that the value of this improvements are all the same. I think this is wildly inaccurate.

I don't think the difference between 'function' and any proposed alternative can even be measured scientifically. Maybe after a year of intense training the difference between typing "function" and "fn" could be measured. The difference for readers could be larger, but does anyone have clear measurements showing more symbolic syntax is always faster/better/cheaper or even that any proposal fits this criteria? I think no. I am not claiming that any such test need to be applied. All I am saying is that the net advantage here is not equal to the other categories.

On the other hand, failing to bind 'this' is something that I believe every single JS developer hits routinely. It has cost them time to recognize and recover. The net advantage of a better bind mechanism still depends upon many issues, but this problem has much bigger impact that eight vs two characters.

The third problem is too obscure for me.

Deciding based on Kevin's data to support an alternative to 'function' but not support bound 'this' would be unwise in my opinion.

jjb

# Axel Rauschmayer (8 years ago)

On the other hand, failing to bind 'this' is something that I believe every single JS developer hits routinely. It has cost them time to recognize and recover. The net advantage of a better bind mechanism still depends upon many issues, but this problem has much bigger impact that eight vs two characters.

+1

And things should be brain-dead simple. That’s what I liked about block lambdas: No need to understand what bound/lexical this actually is, things just worked. With two arrows where each one has different rules (e.g. regarding the body), things are becoming much more complicated.

# Allen Wirfs-Brock (8 years ago)

On Mar 28, 2012, at 8:26 AM, Axel Rauschmayer wrote:

On the other hand, failing to bind 'this' is something that I believe every single JS developer hits routinely. It has cost them time to recognize and recover. The net advantage of a better bind mechanism still depends upon many issues, but this problem has much bigger impact that eight vs two characters.

+1

And things should be brain-dead simple. That’s what I liked about block lambdas: No need to understand what bound/lexical this actually is, things just worked. With two arrows where each one has different rules (e.g. regarding the body), things are becoming much more complicated.

also, +1

we need either fat arrow or block lambda based TCP preserving functions. We don't need thin arrow and we really don't need the confusion it would create.

# Kevin Smith (8 years ago)

we need either fat arrow or block lambda based TCP preserving functions. We don't need thin arrow and we really don't need the confusion it would create.

What about situations where the user wants bound |this|, but no other TCP stuff? Callbacks and a large portion of event handlers fall into this category. Without supporting syntax, these use cases will either have to:

  1. Use "=> do {}", which is heavier, and which will cause unintended

problems (completion leak and invalid use of return).

  1. Use "(function() {}).bind(this)" which is awkward.

  2. Use "var self = this; function() {}" which is also awkward.

# Rick Waldron (8 years ago)

I've been championing this syntax since Dave proposed it as the "tri-lambda syntax". Through this, I've exposed many JavaScript programmers of varying experience (from fellow bocoupers to our JavaScript training sessions - overhwhelmingly actionscript or ruby devs) to the three major pieces:

Just a short hand: let thin = ( a ) -> { return x; };

The general response to this is that it makes complete sense: "just syntax" and "just shorthand" are common "i get it now" phrases. Also, this is highly desirable ie. they want it now.

Has new meaning: let fatexpr = ( y ) => this.x * y;

let fatdoexpr = ( y ) => do { if ( y > 10 ) { this.x * y; } else { this.x = 0; } };

The general response to this is excitement about new possibilities, no more foo.bind(this), no more var self = this;. The semantics and logic is immediately obvious to the ruby devs, the rest "get it" because it looks and acts similar to something they've seen "elsewhere" which is wide and varying.

The only recurring confusion is why:

let fatexpr = ( y ) => this.x * y;

Doesn't look like:

let fatexpr = ( y ) => { this.x * y };

...Nothing to do with -> and =>, but everything to do with expecting to see

a block/function body on the right of the arrow... which the do { expr } seems to mitigate - somehow seeing the curlies there solidifies their own belief that the right side is what they want it to be.

And of course, I've made great use of these (apologies for the reposting)

gist.github.com/2013909

rwldrn/popcorn-js/compare/tri-lambda

rwldrn/popcorn-js/blob/481338a3ab05ad3423c67b70df690bf19977f9bc/popcorn.js

Which has a "seeing is believing" effect.

# Kevin Smith (8 years ago)

Rick provides anecdotal evidence for the idea that a lexically bound |this| form would provide great benefit.

But I believe that using do expressions for lexically binding |this| is going to cause the following problems for beginning and intermediate programmers:

  • Unintentionally leaking the completion value
  • Incorrectly using "return" for those that don't fully understand TCP.

Furthermore, by requiring the slightly awkward keyword "do", we are penalizing a common case (i.e. callbacks and event handlers).

# Kevin Smith (8 years ago)

Just a short hand: let thin = ( a ) -> { return x; };

The general response to this is that it makes complete sense: "just syntax" and "just shorthand" are common "i get it now" phrases. Also, this is highly desirable ie. they want it now.

Despite users wanting this, the numbers seem to show that between object literal method shorthands and a hypothetical function form which binds |this|, a simple short-hand would get little use, and arguably not enough to warrant new syntax.

Rick, I've added the numbers for the original (unarrowed) Popcorn.js to the spreadsheet:

docs.google.com/spreadsheet/ccc?key=0Aro5yQ2fa01xdEJySWxhZ1VoZ0VaWTdldXp4NUtJd3c

Note that out of 96 function expressions, only 6 use dynamic |this| and aren't part of an object literal. This means that at most 6 of those 96 functions would need a simple shorthand for classic functions, if a bound |this| shorthand were provided.

IMO, we can provide the greatest benefit by providing a short-hand which also bind |this|, without any other TCP-ness.

# Kevin Smith (8 years ago)
  • Incorrectly using "return" for those that don't fully understand TCP.

As an illustration, consider this case:

element.onclick = (evt) => do {

    if (this.alreadyWaitingForAjaxResponse)
        return;

    this.startAnAjaxRequest();
};

Presumably the early return will throw an exception, since the binding context has exited before the event handler is called. (Please correct me if I'm wrong.)

# Rick Waldron (8 years ago)

On Wed, Mar 28, 2012 at 3:26 PM, Kevin Smith <khs4473 at gmail.com> wrote:

  • Incorrectly using "return" for those that don't fully understand TCP.

As an illustration, consider this case:

element.onclick = (evt) => do {

    if (this.alreadyWaitingForAjaxResponse)
         return;

    this.startAnAjaxRequest();
};

Presumably the early return will throw an exception, since the binding context has exited before the event handler is called. (Please correct me if I'm wrong.)

I agree with your presumption and would hope that, as it does today, do { return "x"; } would continue to throw the exception SyntaxError: Illegal return statement.

var i = 0; do { i++; return "x"; } while(!i);

SyntaxError: Illegal return statement

var i = 0; do { i++; "x"; } while(!i);

# Brendan Eich (8 years ago)

Kevin Smith wrote:

I hate the CoffeeScript deviation, though. It's just confusing for
anyone who ever learned that fat-arrow binds |this| and thin-arrow
doesn't.

True. On the other hand, "all arrows bind |this|" is also quite simple and easy to remember.

Yes, and I kept the part of the proposal that allows |this| as a leading arrow formal parameter, including with parameter default value. This suggests a slight variation on the strawman, per your suggestion:

x -> { return this.x; } // lexical this for thin arrow

x => this.x // as for fat arrow

(this, x) -> { return this.x; } // dynamic this, five letter syn-tax (this, x) => this.x // ditto for the expression-body form

IOW we make fairly concise, orthogonal syntactic tools for composing (a) lexical vs. bound |this|, and (b) block vs. expression (including object literal) body.

(I used your suggestion of the C#-like shorthand for single-formal-parameter above -- nice!)

# Brendan Eich (8 years ago)

Luke Hoban wrote:

Yeah - I followed the earlier discussion on the data Kevin gathered, which is great input. From the spreadsheet linked in Kevin's mail above, it looks like 81% of function expressions had statement bodies, and>50% did not reference this. While these were cast as BTF candidates, they are also just as much candidates for benefitting from no-frills function shorthand.

That's not clear at all. How many of those <50% that do reference |this| want unbound |this| -- making sure that you take out those covered by method definition shorthands?

Two days ago, Kevin reiterated "[t]he precise way to say it would be that ~90% of function expressions in the code I analyzed were either object literal methods or did not depend on dynamic |this|."

# Brendan Eich (8 years ago)

John J Barton wrote:

On the other hand, failing to bind 'this' is something that I believe every single JS developer hits routinely. It has cost them time to recognize and recover. The net advantage of a better bind mechanism still depends upon many issues, but this problem has much bigger impact that eight vs two characters.

I agree, so I'm now thinking (as just posted in reply to Kevin) that we want -> and => for block and expression bodied short functions, and (this ~~~) at the front of the formal parameter list for dynamic |this| binding, without which the default is lexical |this|.

# Brendan Eich (8 years ago)

Allen Wirfs-Brock wrote:

We don't need thin arrow and we really don't need the confusion it would create.

The case for thin-arrow is body block. Instead rejecting -> and

approving do-expressions results in something a bit overlong (=>do) that

has TCP. And I think it's plausible that this will lead to completion value leaks, wrong-returns, etc. as Kevin suggests.

# Kevin Smith (8 years ago)

If the consensus is that two arrows are too confusing, and we must choose to prefer either object literal or blocks, then the code I sampled suggests that object literals as expression bodies are rather uncommon (only 16 out of 5705 BTF candidates, or 0.2%).

// Not so bad...
x => ({ a: 123 });
# Brendan Eich (8 years ago)

That's the plan.

# Herby Vojčík (8 years ago)

Brendan Eich wrote:

Kevin Smith wrote:

I hate the CoffeeScript deviation, though. It's just confusing for anyone who ever learned that fat-arrow binds |this| and thin-arrow doesn't.

True. On the other hand, "all arrows bind |this|" is also quite simple and easy to remember.

Yes, and I kept the part of the proposal that allows |this| as a leading arrow formal parameter, including with parameter default value. This suggests a slight variation on the strawman, per your suggestion:

x -> { return this.x; } // lexical this for thin arrow x => this.x // as for fat arrow

(this, x) -> { return this.x; } // dynamic this, five letter syn-tax (this, x) => this.x // ditto for the expression-body form

I like this very much. Clear, orthogonal, readable. It would be nice if this could get through.

/be

Herby

P.S.: Dynamic this no-arg function could also use one-arg shorthand?

this => this.x

this -> { return this.x; }

# Brendan Eich (8 years ago)

This is all moot now -- see meeting notes and followups. Thin arrow is not going to make it, we want one arrow. The |this| parameter for opting into dynamic rather than default-lexical |this| also died. Method definition shorthand covers the only strong use-case, as Kevin's analysis shows.

# Irakli Gozalishvili (8 years ago)

Few questions on this new arrow functions:

let foo = x => x * x

  1. What is foo.prototype ?
  2. What does new foo(y) does ?
  3. Is there going to be equivalent of Function for arrow functions ?
  4. Is Function.create(foo) going to work ?
  5. Will foo.call, foo.apply pass in the this ?

-- Irakli Gozalishvili Web: www.jeditoolkit.com

# Brendan Eich (8 years ago)

Irakli Gozalishvili wrote:

Few questions on this new arrow functions:

let foo = x => x * x

  1. What is foo.prototype ?
  2. What does new foo(y) does ?

The idea with arrow function syntax (as opposed to block-lambda revival) was to be as close to "just syntax" for functions. Obviously we've made early-error restrictions but this design goal still stands. So the answers are:

  1. Same as for any user-defined function (a fresh Object instance).
  2. Same as for any user-defined function.

And Object.getPrototypeOf(() => {}) === Function.prototype.

The restriction in ECMA-262 Ed. 5.1 11.4.3, "The typeof Operator", penultimate row in Table 20:

Object (native or host and does implement [[Call]]) "function"

holds, so typeof () => {} === "function".

These are functions, arrow-functions to be precise (so with new syntax and some syntactic restrictions).

  1. Is there going to be equivalent of Function for arrow functions ?

No, see above.

  1. Is Function.create(foo) going to work ?

Function.create is not specified and in Harmony yet, right?

  1. Will foo.call, foo.apply pass in the this ?

Yes, see above.

# Brendan Eich (8 years ago)

Brendan Eich wrote:

Irakli Gozalishvili wrote:

Few questions on this new arrow functions:

let foo = x => x * x

  1. What is foo.prototype ?
  2. What does new foo(y) does ?

The idea with arrow function syntax (as opposed to block-lambda revival) was to be as close to "just syntax" for functions. Obviously we've made early-error restrictions but this design goal still stands. So the answers are:

  1. Same as for any user-defined function (a fresh Object instance).
  2. Same as for any user-defined function.

Oops, I left off something important. Since we agreed on lexical |this| binding, there's no way for the new object to flow into the arrow function. So I'm wrong, the answers are:

  1. Same as for any built-in function: no .prototype property at all.
  2. Arrow-functions lack [[Construct]] so you cannot 'new' them.

This makes arrows like built-ins. They're still functions, per my other answers.

I'll update the strawman (which should be promoted shortly).

Thanks for the good questions!

# Herby Vojčík (8 years ago)

Brendan Eich wrote:

Brendan Eich wrote:

Irakli Gozalishvili wrote:

Few questions on this new arrow functions:

let foo = x => x * x

  1. What is foo.prototype ?
  2. What does new foo(y) does ?

The idea with arrow function syntax (as opposed to block-lambda revival) was to be as close to "just syntax" for functions. Obviously we've made early-error restrictions but this design goal still stands. So the answers are:

  1. Same as for any user-defined function (a fresh Object instance).
  2. Same as for any user-defined function.

Oops, I left off something important. Since we agreed on lexical |this| binding, there's no way for the new object to flow into the arrow function. So I'm wrong, the answers are:

  1. Same as for any built-in function: no .prototype property at all.
  2. Arrow-functions lack [[Construct]] so you cannot 'new' them.

Isn't also answer to "5.":

Q: Will foo.call, foo.apply pass in the this ? A: Yes, see above.

changed? Or is lexical bound this working only for default this, but not for call and apply?

# Brendan Eich (8 years ago)

Herby Vojčík wrote:

Isn't also answer to "5.":

Q: Will foo.call, foo.apply pass in the this ? A: Yes, see above.

changed? Or is lexical bound this working only for default this, but not for call and apply?

Yes, I addressed that in the update to

strawman:arrow_function_syntax

Indeed lexical |this| means you can't pass a wrong-this even via .call or .apply. Thanks,

# Dmitry Soshnikov (8 years ago)

On Thu, Mar 29, 2012 at 12:02 PM, Brendan Eich <brendan at mozilla.org> wrote:

Brendan Eich wrote:

Irakli Gozalishvili wrote:

Few questions on this new arrow functions:

let foo = x => x * x

  1. What is foo.prototype ?
  2. What does new foo(y) does ?

The idea with arrow function syntax (as opposed to block-lambda revival) was to be as close to "just syntax" for functions. Obviously we've made early-error restrictions but this design goal still stands. So the answers are:

  1. Same as for any user-defined function (a fresh Object instance).
  2. Same as for any user-defined function.

Oops, I left off something important. Since we agreed on lexical |this| binding, there's no way for the new object to flow into the arrow function.

Just a small note related to lexical this' -- if it's just a syntactic sugar for thebind' method, then [[Construct]] probably should (for consistency?) work, providing newly created object -- because a bound function delegates to the target's [[Construct]] per ES5.

Dmitry

# Axel Rauschmayer (8 years ago)

Interesting. So x => x * x is not just syntactic sugar for

 function (x) { return x * x }.bind(this)
# Axel Rauschmayer (8 years ago)

My bad. It is, minus [[Construct]] and *.prototype. I misremembered how bind() works.

# Marius Gundersen (8 years ago)

Indeed lexical |this| means you can't pass a wrong-this even via .call or .apply. Thanks,

Isn't this a bad idea? Take for example the very common jQuery callback method, which would look like this:

$("img").on("click", e => $(this).hide());

jQuery (and many other frameworks) do a lot of things with |this| behind the scenes, where it would be very nice to have |this| be set by the framework.

Or is the consensus that the current way of doing this is not good, and should be discurraged?

Marius Gundersen

# Felix Böhm (8 years ago)

How about a "loose-bound" |this|, so that the function falls back to the bound |this| instead of the global scope when no other options are available (or null or undefined are passed to .apply/.bind/.call)?

# Rick Waldron (8 years ago)

On Friday, March 30, 2012 at 6:03 AM, Marius Gundersen wrote:

Indeed lexical |this| means you can't pass a wrong-this even via .call or .apply. Thanks,

Isn't this a bad idea? Take for example the very common jQuery callback method, which would look like this:

$("img").on("click", e => $(this).hide());

jQuery (and many other frameworks) do a lot of things with |this| behind the scenes, where it would be very nice to have |this| be set by the framework.

jQuery provides the same |this| value that you'd get using addEventListener, so this issue would exist in the DOM as well.

More pointedly, lexical |this| prevents modifying |this| via apply and call

I had hoped for thin arrow to lighten the keystroke load here.

# Kevin Smith (8 years ago)

jQuery provides the same |this| value that you'd get using addEventListener, so this issue would exist in the DOM as well.

With addEventListener it's not as much of an issue, because you already have a reference to the element in question when you register the event.

With jQuery, the |this| parameter is also duplicated as event.currentTarget, which is admittedly a few more keystrokes:

// This will work:
$("body").on("click", e => $(e.currentTarget).hide());

// Nothing wrong with classic, if you want dynamic this:
$("body").on("click", function() { $(this).hide(); });

// Or maybe change the framework to better take advantage of arrows?:
$("body").on("click", e => $(e).hide());

FWIW, I randomly took a link from the jQuery home page (dell.com) and ran the code on that site (from an inner page, not including jQuery itself) through the analyzer, and added the results to the spreadsheet. The results are pretty typical: 64% BTF candidates, 79% BTF candidates or object literal methods.

A couple of observations:

  1. Of course jQuery is hugely important in the javascript world, but that doesn't necessarily mean that a hugely disproportionate share of function expressions are jQuery event handlers which use |this|.

  2. Frameworks that currently use |this| as a general parameter passing mechanism may find that there are better ways to pass that data, given arrow functions and the ability of users to take advantage of lexical |this|.

  3. There's nothing wrong with long-hand, if that's what you want.

# Kevin Smith (8 years ago)
// Or maybe change the framework to better take advantage of arrows?:
$("body").on("click", e => $(e).hide());

To clarify, the $ function could hypothetically take an event object and return the set containing event.currentTarget.

# Rick Waldron (8 years ago)

[snip]

// Or maybe change the framework to better take advantage of arrows?:
$("body").on("click", e => $(e).hide());

As much as I would love this, it's not realistic. We're stuck with the

unfortunate burden of supporting a consistent behaviour regardless of platform, ie jQuery will only do things in Chrome Canary or Firefox Nightly that can also work, identically, in IE6; we must also do so concisely, or suffer the wrath of "bloat" accusations.

A programmer can dream though... one day! :D

Rick

[snip]

# Kevin Smith (8 years ago)

What about something similar to this in the $ function?

// Handle $(event)
if ( selector.currentTarget && selector.currentTarget.nodeType ) {
    this.context = this[0] = selector.currentTarget;
    this.length = 1;
    return this;
}
# Claus Reinke (8 years ago)
  1. Frameworks that currently use |this| as a general parameter passing mechanism may find that there are better ways to pass that data, given arrow functions and the ability of users to take advantage of lexical |this|.

  2. There's nothing wrong with long-hand, if that's what you want.

How about using a long-hand library function to convert the implicit dynamic this into an explicit parameter for short-hand functions?

function getthis(callback) { return function(..args) { return callback(this,..args) } }

wecallyou( getthis( (this,..args)=>... ) )

Wouldn't that work?

Claus

# Brendan Eich (8 years ago)

We do not want to delegate to a target function that can [[Construct]], because there is no such target function -- we're not trying to sugar .bind on a full function. That is too expensive and general (no pre-args, no full function under the hood).

Lexical-only |this| binding means no [[Construct]] and no .prototype for arrow functions. I'm ok with this.

The concern about JQuery or other code wanting to dynamically bind |this| is good but not fatal. Use a long-hand function. I've heard people complain about JQuery's "pronoun trouble" enough to take it with a grain of salt. I know, JQuery, but still: use a long function.

# Axel Rauschmayer (8 years ago)

Axel Rauschmayer wrote:

My bad. It is, minus [[Construct]] and *.prototype. I misremembered how bind() works.

On Mar 30, 2012, at 0:01 , Axel Rauschmayer wrote:

Interesting. So x => x * x is not just syntactic sugar for

function (x) { return x * x }.bind(this)

On Mar 31, 2012, at 2:54 , Brendan Eich wrote:

We do not want to delegate to a target function that can [[Construct]], because there is no such target function -- we're not trying to sugar .bind on a full function. That is too expensive and general (no pre-args, no full function under the hood).

Ah, good. But one can use the above (pseudo-)desugaring to predict the behavior of arrow functions, right? That is, there is no observable difference.

# Dmitry Soshnikov (8 years ago)

On Apr 1, 2012, at 12:12 AM, Axel Rauschmayer wrote:

Axel Rauschmayer wrote:

My bad. It is, minus [[Construct]] and *.prototype. I misremembered how bind() works.

On Mar 30, 2012, at 0:01 , Axel Rauschmayer wrote:

Interesting. So x => x * x is not just syntactic sugar for

function (x) { return x * x }.bind(this)

On Mar 31, 2012, at 2:54 , Brendan Eich wrote:

We do not want to delegate to a target function that can [[Construct]], because there is no such target function -- we're not trying to sugar .bind on a full function. That is too expensive and general (no pre-args, no full function under the hood).

Ah, good. But one can use the above (pseudo-)desugaring to predict the behavior of arrow functions, right? That is, there is no observable difference.

There is, again, the difference in terms of delegation to the target's [[Construct]] in case of a bound function, see the spec ("bound" per ES5, of course, since, as Brendan notices, it's not just a syntactic sugar, but a new special type of functions).

Dmitry

# Axel Rauschmayer (8 years ago)

Ah, good. But one can use the above (pseudo-)desugaring to predict the behavior of arrow functions, right? That is, there is no observable difference.

There is, again, the difference in terms of delegation to the target's [[Construct]] in case of a bound function, see the spec ("bound" per ES5, of course, since, as Brendan notices, it's not just a syntactic sugar, but a new special type of functions).

OK. Ignoring [[Construct]] and .prototype, any other differences?

# Dmitry Soshnikov (8 years ago)

On Apr 1, 2012, at 12:34 AM, Axel Rauschmayer wrote:

Ah, good. But one can use the above (pseudo-)desugaring to predict the behavior of arrow functions, right? That is, there is no observable difference.

There is, again, the difference in terms of delegation to the target's [[Construct]] in case of a bound function, see the spec ("bound" per ES5, of course, since, as Brendan notices, it's not just a syntactic sugar, but a new special type of functions).

OK. Ignoring [[Construct]] and .prototype, any other differences?

Well, "ES5-bounds" also do not have prototype' property, but delegate to the target'sprototype'. However, yes, there is the (main) difference in respect of supporting TCP (if I understand correctly, since had no time to follow the complete thread) -- return and break/continue jumps to the parent frame instead of working with the function itself.

Lexical this' is the only similar thing to bound functions, so we should not call => functions as synonym to bound functions. You may say, => function _as well as_ a bound capturesthis' lexically, but in contrast with it, it has other features. In my later analysis, I'll specify them as a new type of functions -- AF (Arrow Function) -- in addition to FE, FD, NFE, BF, etc., with many own features, but not just a syntactic sugar -- neither for FE, nor for BF.

Dmitry

# Axel Rauschmayer (8 years ago)

On Apr 1, 2012, at 12:34 AM, Axel Rauschmayer wrote:

Ah, good. But one can use the above (pseudo-)desugaring to predict the behavior of arrow functions, right? That is, there is no observable difference.

There is, again, the difference in terms of delegation to the target's [[Construct]] in case of a bound function, see the spec ("bound" per ES5, of course, since, as Brendan notices, it's not just a syntactic sugar, but a new special type of functions).

OK. Ignoring [[Construct]] and .prototype, any other differences?

Well, "ES5-bounds" also do not have prototype' property, but delegate to the target'sprototype'. However, yes, there is the (main) difference in respect of supporting TCP (if I understand correctly, since had no time to follow the complete thread) -- return and break/continue jumps to the parent frame instead of working with the function itself.

Arrow functions do not adhere to TCP. Everything you need to know is here: strawman:arrow_function_syntax

# Dmitry Soshnikov (8 years ago)

Oh, wait, just have read Crock's article on => functions. A Python's style of passing manual `this'? That's interesting (why it's not specified on the wiki? where Crockford took it from? did you discuss it in a close ECMA meeting?). Inconsistent again with other functions.

So, let's see, overall we have .. 6 types of functions in JS, and all have their own specific features. That's again interesting, if won't cause confusion.

Dmitry

# Dmitry Soshnikov (8 years ago)

On Apr 1, 2012, at 1:22 AM, Axel Rauschmayer wrote:

On Apr 1, 2012, at 12:34 AM, Axel Rauschmayer wrote:

Ah, good. But one can use the above (pseudo-)desugaring to predict the behavior of arrow functions, right? That is, there is no observable difference.

There is, again, the difference in terms of delegation to the target's [[Construct]] in case of a bound function, see the spec ("bound" per ES5, of course, since, as Brendan notices, it's not just a syntactic sugar, but a new special type of functions).

OK. Ignoring [[Construct]] and .prototype, any other differences?

Well, "ES5-bounds" also do not have prototype' property, but delegate to the target'sprototype'. However, yes, there is the (main) difference in respect of supporting TCP (if I understand correctly, since had no time to follow the complete thread) -- return and break/continue jumps to the parent frame instead of working with the function itself.

Arrow functions do not adhere to TCP. Everything you need to know is here: strawman:arrow_function_syntax

Yes, thanks I've read it. But probably I misunderstood the description, but what then is the following mean?

"... bind return in the Block body case so it returns from the immediately enclosing arrow function, and preclude breakand continue from referencing statements outside the immediately enclosing arrow function."

Isn't it for supporting TCP? (sorry if it was already discussed and explained before, that's said, unfortunately hadn't time to join earlier)

Dmitry

# Axel Rauschmayer (8 years ago)

No, that paraphrases “no TCP, everything behaves like in normal functions”. That is, it describes how return, break, continue currently work in functions.

[[[Sent from a mobile device. Please forgive brevity and typos.]]]

Dr. Axel Rauschmayer axel at rauschma.de Home: rauschma.de Blog: 2ality.com

# Dmitry Soshnikov (8 years ago)

On Apr 1, 2012, at 1:40 AM, Dmitry Soshnikov wrote:

On Apr 1, 2012, at 1:22 AM, Axel Rauschmayer wrote:

On Apr 1, 2012, at 12:34 AM, Axel Rauschmayer wrote:

Ah, good. But one can use the above (pseudo-)desugaring to predict the behavior of arrow functions, right? That is, there is no observable difference.

There is, again, the difference in terms of delegation to the target's [[Construct]] in case of a bound function, see the spec ("bound" per ES5, of course, since, as Brendan notices, it's not just a syntactic sugar, but a new special type of functions).

OK. Ignoring [[Construct]] and .prototype, any other differences?

Well, "ES5-bounds" also do not have prototype' property, but delegate to the target'sprototype'. However, yes, there is the (main) difference in respect of supporting TCP (if I understand correctly, since had no time to follow the complete thread) -- return and break/continue jumps to the parent frame instead of working with the function itself.

Arrow functions do not adhere to TCP. Everything you need to know is here: strawman:arrow_function_syntax

Yes, thanks I've read it. But probably I misunderstood the description, but what then is the following mean?

"... bind return in the Block body case so it returns from the immediately enclosing arrow function, and preclude breakand continue from referencing statements outside the immediately enclosing arrow function."

Isn't it for supporting TCP? (sorry if it was already discussed and explained before, that's said, unfortunately hadn't time to join earlier)

Ah, ignore this, I skipped the last note in the Rationale section related to TCP.

Dmitry

# Axel Rauschmayer (8 years ago)

AFAIKT, Crockford is referring to an older version of the proposal.

[[[Sent from a mobile device. Please forgive brevity and typos.]]]

Dr. Axel Rauschmayer axel at rauschma.de Home: rauschma.de Blog: 2ality.com

# Dmitry Soshnikov (8 years ago)

On Apr 1, 2012, at 1:45 AM, Axel Rauschmayer wrote:

No, that paraphrases “no TCP, everything behaves like in normal functions”. That is, it describes how return, break, continue currently work in functions.

Yes, thanks, I missed this.

Dmitry

# Brendan Eich (8 years ago)

Dmitry Soshnikov wrote:

Oh, wait, just have read Crock's article on => functions. A Python's style of passing manual `this'? That's interesting (why it's not specified on the wiki?

See doku.php?id=strawman:arrow_function_syntax&rev=1332877190 -- removed by next revision:

2012/03/29 06:05 show differences to current version

doku.php?id=strawman:arrow_function_syntax&rev=1333001151&do=diff

strawman:arrow_function_syntax doku.php?id=strawman:arrow_function_syntax&rev=1333001151

Updates per TC39 meeting today brendan

The optional leading |this| parameter without an Initialiser (parameter default value) was long-hand for dynamic-this binding, the "thin arrow" (->) of previous versions. We agreed with Waldemar on cutting down a

list of five "iffy" design decisions, see his meeting notes. Thin-arrow and leading |this| fell quickly, and the desire for "one arrow" was clear.

The detailed rationale for killing leading |this| is less clear, but without it we have fewer function forms as you note (not sure where your 6 count came from, but no worries). The "YAGNI" and "dynamic-this is a foot-gun" arguments favored leaving out -> or (this, arg1, ~~~ argN)

syntax. These are not absolute judgments, obviously. They're KISS and "when in doubt, leave it out" relative judgments.

# Quildreen Motta (8 years ago)

Is there any particular reason optionally dynamic `this' got ditched from the current arrow syntax proposal? It's one thing that, I think, would make it more useful than just being used for inline callbacks.

Plus, with a syntax like:


let ps = { lookahead: (this, n) => { this.current().slice(0, n || 1) } , current: (this) => { this.text.slice(this.offset) } , move: (this, n) => { this.clone(this.text, this.offset + 1) } , clone: (this, text, offset) => { let r = Object.create(this) , r.offset = offset || 0 , r.text = text || '' } }

You'd perhaps avoid some of the confusion on dynamic this' by making it explicit thatthis' is just an additional parameter passed over to the function — albeit implicitly. It seems to work for Python, though there `self' is bound at the instantiation time.

# Brendan Eich (8 years ago)

Quildreen Motta wrote:

You'd perhaps avoid some of the confusion on dynamic this' by making it explicit thatthis' is just an additional parameter passed over to the function — albeit implicitly. It seems to work for Python, though there `self' is bound at the instantiation time.

Yes, that's why I proposed it. EIBTI.

Alas to reach consensus, we minimize. This happened with private names => private name objects (API only, no "privat x" declarations), and now

we are trying to add private declarations.back into ES6. (I hope we succeed.)

Could try adding explicit-this-parameterization too, but it's another straw on the camel's back.

# Allen Wirfs-Brock (8 years ago)

On Apr 1, 2012, at 8:07 AM, Quildreen Motta wrote:

Is there any particular reason optionally dynamic `this' got ditched from the current arrow syntax proposal? It's one thing that, I think, would make it more useful than just being used for inline callbacks.

Yes, because it is unnecessary and would just add more confusion to the already too confused understanding of "this" by most JS programmers.

Plus, with a syntax like:


let ps = { lookahead: (this, n) => { this.current().slice(0, n || 1) } , current: (this) => { this.text.slice(this.offset) } , move: (this, n) => { this.clone(this.text, this.offset + 1) } , clone: (this, text, offset) => { let r = Object.create(this) , r.offset = offset || 0 , r.text = text || '' } }

How is the above better (ignoring any controversy about line-beginning separators) than:

let ps = { lookahead ( n) { this.current().slice(0, n || 1) }, current() { this.text.slice(this.offset) }, move(n) { this.clone(this.text, this.offset + 1) }, clone(text, offset) { let r = Object.create(this); r.offset = offset || 0; r.text = text || ''; } }

You'd perhaps avoid some of the confusion on dynamic this' by making it explicit thatthis' is just an additional parameter passed over to the function — albeit implicitly.

"this" isn't just an additional parameter and trying to turn it into such just creates more confusions. this (aka self) is a characteristic feature of object-oriented methods, not of functions. Methods only have meaning in the context of an object. It is essential to the OO programming model that this/self is dynamically bounds to the object that is the target of each method invocation. In a well designed OO language the method invocation target is syntactically distinct from "other parameters". If this didn't have special OO semantics there would be no reason to have special syntax and semantics for defining/accessing this within a function. However, in that case you don't have a OO language, instead you have a functional language that is used to provide a (low fidelity) simulation of OO constructs.

The confusion about this in JS comes from at least four things.

  1. It is too easy to define a "method" (a function that uses a dynamic per-invocation this binding) that is not directly associated with an object (or class/prototype). eg: var f = function() {this.foo()};
  2. In classic JS there was no syntax that distinguished the intended definition of a method from a function, other than the appearance of this in the body of the function.
  3. It is too easy to extract a method from an object (or class/prototype), breaking the association between the method and object. eg: var g = String.splice;
  4. It is too easy to call a disassociated method without an object association as if it was a regular function eg: f();

The confusion is only worsen by things like jQuery choosing to exploit such disassociated methods to create non-OO idioms using this

It seems to work for Python, though there `self' is bound at the instantiation time.

I don't believe this is correct, if you mean object instantiation time. You can view obj.meth in Python as a left-curry operation that creates a new function where the first parameter of meth is pre-bound to obj. This is why Python does not have issue 3 above.

Regardless, Python is also a retrofitted OO language where arguably objects are even less central to the language than in JS.

# Brendan Eich (8 years ago)

Allen Wirfs-Brock wrote:

Regardless, Python is also a retrofitted OO language where arguably objects are even less central to the language than in JS.

Funny you write this, as Python is arguably more OO than JS even with its explicit self parameter for class-defined methods. Or perhaps Python is less functional because of lack of fully expressive lambda (GvR argued against on OO grounds, IIRC).

One thing you undersell: the ability in JS to borrow, share, and wrap methods. This is not a justification for the |this| confusion evident from user experience of JS, but it is something hard to do in more rigid languages.

# Claus Reinke (8 years ago)

Is there any particular reason optionally dynamic `this' got ditched from the current arrow syntax proposal? It's one thing that, I think, would make it more useful than just being used for inline callbacks.

You can get that back without changing the proposal (ES6 comments, ES5 code):

// wrap this-less f to capture dynamic 'this' as explicit parameter // function fn(f) { return function(..args) { return f(this,..args) } } // function fn(f) { return function() { return f.apply(null,[this].concat(Array.prototype.slice.call(arguments))) } }

// access dynamic 'this' as lexical 'it' // obj = { id: "obj", f: fn( (it,msg)=>{ console.log(msg+it.id) } ) } // var obj = { id: "obj",f: fn( function(it,msg){ console.log(msg+it.id) } ) };

obj.f("hi, "); // outputs "hi, obj"

Claus

# Quildreen Motta (8 years ago)

On 01/04/12 15:08, Allen Wirfs-Brock wrote:

On Apr 1, 2012, at 8:07 AM, Quildreen Motta wrote:

How is the above better (ignoring any controversy about line-beginning separators) than:

let ps = { lookahead ( n) { this.current().slice(0, n || 1) }, current() { this.text.slice(this.offset) }, move(n) { this.clone(this.text, this.offset + 1) }, clone(text, offset) { let r = Object.create(this); r.offset = offset || 0; r.text = text || ''; } }

I forgot the object literal syntax was also getting a lightweight method definition syntax, my bad.

You'd perhaps avoid some of the confusion on dynamic this' by making it explicit thatthis' is just an additional parameter passed over to the function — albeit implicitly.

"this" isn't just an additional parameter and trying to turn it into such just creates more confusions. this (aka self) is a characteristic feature of object-oriented /methods/, not of functions. Methods only have meaning in the context of an object. It is essential to the OO programming model that this/self is dynamically bounds to the object that is the target of each method invocation. In a well designed OO language the method invocation target is syntactically distinct from "other parameters". If this didn't have special OO semantics there would be no reason to have special syntax and semantics for defining/accessing this within a function. However, in that case you don't have a OO language, instead you have a functional language that is used to provide a (low fidelity) simulation of OO constructs.

Hm, perhaps because of my mostly functional background — JS is the only OO language I've actually spent much time learning, — I've always seen methods as higher-order functions (target -> a... -> b), and the `object.method()' invocation pattern as just coupling single dispatching with a nice infix function invocation syntax.

Maybe I'm thinking more in terms of possible implementation details than concepts, which I'm not as familiar with.

It seems to work for Python, though there `self' is bound at the instantiation time.

I don't believe this is correct, if you mean object instantiation time. You can view obj.meth in Python as a left-curry operation that creates a new function where the first parameter of meth is pre-bound to obj. This is why Python does not have issue 3 above.

Ah, yes, you're right. The currying is done at the lookup/dispatch time.

# Dmitry Soshnikov (8 years ago)

On Apr 1, 2012, at 7:52 AM, Brendan Eich wrote:

Dmitry Soshnikov wrote:

Oh, wait, just have read Crock's article on => functions. A Python's style of passing manual `this'? That's interesting (why it's not specified on the wiki?

See doku.php?id=strawman:arrow_function_syntax&rev=1332877190 -- removed by next revision:

2012/03/29 06:05 show differences to current version doku.php?id=strawman:arrow_function_syntax&rev=1333001151&do=diff strawman:arrow_function_syntax doku.php?id=strawman:arrow_function_syntax&rev=1333001151 Updates per TC39 meeting today brendan

The optional leading |this| parameter without an Initialiser (parameter default value) was long-hand for dynamic-this binding, the "thin arrow" (->) of previous versions. We agreed with Waldemar on cutting down a list of five "iffy" design decisions, see his meeting notes. Thin-arrow and leading |this| fell quickly, and the desire for "one arrow" was clear.

The detailed rationale for killing leading |this| is less clear, but without it we have fewer function forms as you note (not sure where your 6 count came from, but no worries). The "YAGNI" and "dynamic-this is a foot-gun" arguments favored leaving out -> or (this, arg1, ~~~ argN) syntax. These are not absolute judgments, obviously. They're KISS and "when in doubt, leave it out" relative judgments.

OK, gottcha. Thanks, Brendan.

Yes, currently avoiding leading `this' seems less confusing.

Dmitry

P.S.:

Offtopic footnote. 6 types:

  1. Function Declaration (FD). Features: "hoisting", always named.

  2. Function Expression (FE). Features: no "hoisting", available for immediately invoked functions (IIF).

  3. Named Function Expressions (NFE). Features: no "hoisting", the same as FE actually, but because of many old (?) bugs/features, especially in IE, I put them in the separate type. Since ES5 strict they are just FE if implemented correctly.

  4. Functions created via Function constructor (FF). Features: only global in the scope chain.

  5. Bound functions (BF). Features: captures this', but "dynamic"this' in case of new', noprototype', no [[Scope]], no [[Construct]], but delegation to the target's, etc.

  6. Arrow functions (AF). Features: captured this', capturedthis' even in case of `new'.

# Jorge (8 years ago)

On Apr 2, 2012, at 6:48 AM, Dmitry Soshnikov wrote:

P.S.:

Offtopic footnote. 6 types:

  1. Function Declaration (FD). Features: "hoisting", always named.

  2. Function Expression (FE). Features: no "hoisting", available for immediately invoked functions (IIF).

  3. Named Function Expressions (NFE). Features: no "hoisting", the same as FE actually, but because of many old (?) bugs/features, especially in IE, I put them in the separate type. Since ES5 strict they are just FE if implemented correctly.

  4. Functions created via Function constructor (FF). Features: only global in the scope chain.

And always anonymous.

  1. Bound functions (BF). Features: captures this', but "dynamic"this' in case of new', noprototype', no [[Scope]], no [[Construct]], but delegation to the target's, etc.

No [[Scope]]? I must be missing something! Given this code:

bound= (function a(i) { return function b () { return i }.bind(null) })(27); bound() --> 27

How can bound() resolve i without a [[Scope]] ?

  1. Arrow functions (AF). Features: captured this', capturedthis' even in case of `new'.

And [[Extensible]] === false... I wonder why, why non-extensible ?

# Brendan Eich (8 years ago)

Jorge wrote:

No [[Scope]]? I must be missing something! Given this code:

bound= (function a(i) { return function b () { return i }.bind(null) })(27);

bound() --> 27

How can bound() resolve i without a [[Scope]] ?

By delegating to bound()'s [[TargetFunction]], which does have a [[Scope]] -- see ES5 15.3.4.5.1 and 15.3.4.5.2.

  1. Arrow functions (AF). Features: captured this', capturedthis' even in case of `new'.

And [[Extensible]] === false... I wonder why, why non-extensible ?

No, arrows are extensible -- where did you see [[Extensible]] === false?

# Jorge (8 years ago)

On Apr 2, 2012, at 2:12 PM, Brendan Eich wrote:

Jorge wrote:

No [[Scope]]? I must be missing something! Given this code:

bound= (function a(i) { return function b () { return i }.bind(null) })(27); bound() --> 27

How can bound() resolve i without a [[Scope]] ?

By delegating to bound()'s [[TargetFunction]], which does have a [[Scope]] -- see ES5 15.3.4.5.1 and 15.3.4.5.2.

Oh, I see. Thank you!

  1. Arrow functions (AF). Features: captured this', capturedthis' even in case of `new'.

And [[Extensible]] === false... I wonder why, why non-extensible ?

No, arrows are extensible -- where did you see [[Extensible]] === false?

I saw it here: www.yuiblog.com/blog/2012/03/30/what-is-the-meaning-of-this

"Function objects are mutable like other objects. This will make the securing of JavaScript more difficult because every function object can be used as a channel to facilitate unwanted collusion between widgets. ES5 provides tools to freeze functions, making them immutable, but the tools are really difficult to use for that purpose. The Sixth Edition of ECMAScript may correct all of these problems." ... "Fat arrow functions do not have prototype properties, which makes them cheaper to make. They are immutable." ... "You will need the old functions to make mutable functions, although I don’t recommend those either."

# Brendan Eich (8 years ago)

Jorge wrote:

I saw it here:www.yuiblog.com/blog/2012/03/30/what-is-the-meaning-of-this

Right -- I think Doug was remembering the "Harmony of My Dreams" sharp-functions (brendaneich.com/2011/01/harmony-of-my-dreams/#sharp_functions), but arrows express mutable function objects per

strawman:arrow_function_syntax

which is the current source of truthiness.

I left a comment about this on the YUI blog, saw it post yesterday, but it's gone now. Cc'ing Doug.

# Douglas Crockford (8 years ago)

On 4/2/2012 8:24 AM, Brendan Eich wrote:

Jorge wrote:

I saw it here:www.yuiblog.com/blog/2012/03/30/what-is-the-meaning-of-this

Right -- I think Doug was remembering the "Harmony of My Dreams" sharp-functions (brendaneich.com/2011/01/harmony-of-my-dreams/#sharp_functions), but arrows express mutable function objects per

strawman:arrow_function_syntax

which is the current source of truthiness.

I left a comment about this on the YUI blog, saw it post yesterday, but it's gone now. Cc'ing Doug.

It seems I misunderstood what we were agreeing to. I think the (this...) form is critically important, and the immutability thing as well.

# Brendan Eich (8 years ago)

Douglas Crockford wrote:

On 4/2/2012 8:24 AM, Brendan Eich wrote:

Jorge wrote:

I saw it here:www.yuiblog.com/blog/2012/03/30/what-is-the-meaning-of-this

Right -- I think Doug was remembering the "Harmony of My Dreams" sharp-functions (brendaneich.com/2011/01/harmony-of-my-dreams/#sharp_functions), but arrows express mutable function objects per

strawman:arrow_function_syntax

which is the current source of truthiness.

I left a comment about this on the YUI blog, saw it post yesterday, but it's gone now. Cc'ing Doug.

It seems I misunderstood what we were agreeing to. I think the (this...) form is critically important, and the immutability thing as well.

We had an agreement last year in TC39 to avoid making new shorter function syntax implicitly freeze where the new shorter syntax falls in full function syntax's general body-plan. This was the impetus for the # prefix, which also can apply to object and array literals.

We're not going to implicitly freeze arrows. It was never in the strawman, or on the whiteboard during the negotiations.

I agree that leading |this| could be important for dynamic non-method use-cases, but those are relatively rare (let's not discount JQuery, but again, it could use long functions and survive). We could put leading-this-parameterization on the agenda for May, but we'll have to be careful not to lose consensus on arrows.

# Dmitry Soshnikov (8 years ago)

On Mon, Apr 2, 2012 at 12:47 PM, Brendan Eich <brendan at mozilla.com> wrote:

Douglas Crockford wrote:

On 4/2/2012 8:24 AM, Brendan Eich wrote:

Jorge wrote:

I saw it here:<www.yuiblog.comblog/2012/03/30/what-is-the- meaning-of-thiswww.yuiblog.com/blog/2012/03/30/what-is-the-meaning-of-this>

Right -- I think Doug was remembering the "Harmony of My Dreams" sharp-functions (brendaneich.com/201101/harmony-of-my-dreams/# sharp_functionsbrendaneich.com/2011/01/harmony-of-my-dreams/#sharp_functions ), but arrows express mutable function objects per

doku.php?id=strawman:arrow_ function_syntaxstrawman:arrow_function_syntax

which is the current source of truthiness.

I left a comment about this on the YUI blog, saw it post yesterday, but it's gone now. Cc'ing Doug.

It seems I misunderstood what we were agreeing to. I think the (this...) form is critically important, and the immutability thing as well.

We had an agreement last year in TC39 to avoid making new shorter function syntax implicitly freeze where the new shorter syntax falls in full function syntax's general body-plan. This was the impetus for the # prefix, which also can apply to object and array literals.

We're not going to implicitly freeze arrows. It was never in the strawman, or on the whiteboard during the negotiations.

I agree that leading |this| could be important for dynamic non-method use-cases, but those are relatively rare (let's not discount JQuery, but again, it could use long functions and survive). We could put leading-this-parameterization on the agenda for May, but we'll have to be careful not to lose consensus on arrows.

Exactly -- I do remember leading `this' of #-functions, and even talked myself about it on one of the confs, but I was surprised to see it in Doug's article on -> functions (now it's clear that it was in wiki as well,

but has been removed).

Notice though, that providing such a Pythonic manual leading this' just makes the same manual "this-manipulations", but from the vice-versa side: In case of normal functions you work implicitly with the dynamicthis', but should manually capture it using bind' or saving to a variable if needed staticthis'. In case of -> functions with the leading `this' you

do the same, but capture dynamic `this' -- still manually. Which seems the same job to do. I.e. two vice-versa in semantics, but still the same, function types.

Probably dynamic this' is really rare in this cases and nobody will use leadingthis', but when people will need it, perhaps it's good to provide it. Otherwise, they will have to mix different types of functions by different reasons. In one case a user uses arrow function for shortness, in other case she should switch to "old-fashion" function expression, because she says: "hey, I need dynamic this', but those guys didn't give me such ability". Lately, I believe users will work out some common patterns and some of the function types will just die and desperate. The condition for this -- a function should have all the possible ways of usage/compromises (short syntax, ability of dynamic/staticthis', frozen).

Dmitry

# Allen Wirfs-Brock (8 years ago)

On Apr 2, 2012, at 12:47 PM, Brendan Eich wrote:

...

We had an agreement last year in TC39 to avoid making new shorter function syntax implicitly freeze where the new shorter syntax falls in full function syntax's general body-plan. This was the impetus for the # prefix, which also can apply to object and array literals.

We're not going to implicitly freeze arrows. It was never in the strawman, or on the whiteboard during the negotiations.

I agree that leading |this| could be important for dynamic non-method use-cases, but those are relatively rare (let's not discount JQuery, but again, it could use long functions and survive). We could put leading-this-parameterization on the agenda for May, but we'll have to be careful not to lose consensus on arrows.

Other than the JQuery style misuse of this, what are the use cases? If you want to bind this, why wouldn't a method invocation on an objet be involved?

No doubt I'm repeating myself fro a previous message, so I'll be more forceful. "dynamic this" is a core OO concept but "dynamic this" in a non-method context is an abomination. A non-method "dynamic this" is essentially a leak in the implementation of the object abstract. This leak is an extreme source of confusion among JS programmers. We shouldn't be adding things that expand the potential for confusion. Allowing the this keyword as a formal parameter of arrow functions would be terrible from that perspective.

With concise methods and arrow functions we have an opportunity to cleanly separate the most common definitions of methods and regular (non-method) functions. You should use concise methods in object literals (and hopefully class definition) when you are actually defining a method and need to reference the this keyword.. You should use an arrow function in most non-method situations. For corner cases, legacy libraries, and legacy programmers long form function declarations/expressions are still available.

There are two abnormal situations that we should consider: calling a "concise method" without providing a this value and calling an "arrow function" in a manner that explicitly provides a this value (other than undefined). I need to think more about this, but perhaps we should throw in those situations. For example:

let obj = new class( bar() { /* do something useful */} foo () {this.bar()} }; let f = arg => doSomething(arg);

let FOO=obj.foo;

//normal usage obj.bar(); obj.foo(42); obj.bar.call(obj); obj.foo.apply({bar() {doSomethingElse()},[42]); f(); f.call(undefined,42);

//potential, straightforward runtime errors FOO(42); //could be error, trying to call a method without providing a this value f.call(obj, 42); //could be error, trying to pass a this value to an arrow function

//less straightforward possible errors obj.callback = f; //logically a data property storing a function not a method obj.callback((42); //could be error trying to call a arrow function as a method, but the intent may be: (0, obj.callback)(42); //never an error, not a method call or: (f=>f(42))(obj.callback); //never an error,normal call of an arrow function

I see potential value in dynamic errors for the straightforward cases, however the conceptual ambiguity (either a method call or call of functional value retrieved from an object) of obj.f() may be enough to kill the idea.

# Brendan Eich (8 years ago)

Allen Wirfs-Brock wrote:

No doubt I'm repeating myself fro a previous message, so I'll be more forceful. "dynamic this" is a core OO concept but "dynamic this" in a non-method context is an abomination.

The problem is "non-method context" is ill-defined in JS (ES5.1 or lower), without extensions.

With extensions such as method definition shorthand in object literals, maybe -- but that has not yet been demonstrated.

Trying to catch some (but not all as you allow) wrong-this patterns dynamically will have false positives as well as false negatives, and smells bad to me.

I agree we don't need optional leading-this parameterization of arrows, of course. That's why I cut it. Doug was not the only one to bring it up again, though. I'm happy to hang tough against it, and I hope Doug is too now, based on this thread.

# Jorge (8 years ago)

On Apr 2, 2012, at 9:47 PM, Brendan Eich wrote:

Douglas Crockford wrote:

It seems I misunderstood what we were agreeing to. I think the (this...) form is critically important, and the immutability thing as well.

(...)

I agree that leading |this| could be important for dynamic non-method use-cases, but those are relatively rare (let's not discount JQuery, but again, it could use long functions and survive). We could put leading-this-parameterization on the agenda for May, but we'll have to be careful not to lose consensus on arrows.

I was chatting this evening with a friend about this (ruby) thing:

class Numeric (Math.methods - Module.methods - ["hypot", "ldexp"]).each do |method| define_method method do Math.send method, self end end end

And I showed him how one could do that easily in JavaScript:

Object.getOwnPropertyNames(Math).forEach(function (key) { if (typeof Math[key] === 'function') { Number.prototype[key]= function () { return Mathkey; }; } });

Then I thought, let's see how would that look like with arrows ?

Object.getOwnPropertyNames(Math).forEach((key) => { if (typeof Math[key] === 'function') Number.prototype[key]= () => Mathkey; });

And it turns out that here, the outer/enclosing context this isn't the one you want/need. You'd need a dynamically bound this instead:

Object.getOwnPropertyNames(Math).forEach((key) => { if (typeof Math[key] === 'function') Number.prototype[key]= (this) => Mathkey; });

and thus the this-in-the-parameters-list trick.

I don't think it's such a rare case: Inside a constructor function called with new, yes, this is most likely going to be the right this always, but when you are building objects with a factory (e.g. with a .create() method), the enclosing this usually isn't going to be the right one.

# Kevin Smith (8 years ago)

Object.getOwnPropertyNames(Math).forEach((key) => { if (typeof Math[key] === 'function') Number.prototype[key]= () => Mathkey; });

Hi Jorge,

Here you are defining a method, for which arrows are inappropriate. Long-hand functions are appropriate in this case.

Object.getOwnPropertyNames(Math).forEach(key => {
    if (typeof Math[key] === "function")
        Number.prototype[key] = function() { return Math[key](this); };
});

No one's attempting to deprecate long-hand functions. Arrow functions fill a different need.

# Allen Wirfs-Brock (8 years ago)

On Apr 2, 2012, at 4:22 PM, Jorge wrote:

On Apr 2, 2012, at 9:47 PM, Brendan Eich wrote:

Douglas Crockford wrote:

It seems I misunderstood what we were agreeing to. I think the (this...) form is critically important, and the immutability thing as well.

(...)

I agree that leading |this| could be important for dynamic non-method use-cases, but those are relatively rare (let's not discount JQuery, but again, it could use long functions and survive). We could put leading-this-parameterization on the agenda for May, but we'll have to be careful not to lose consensus on arrows.

I was chatting this evening with a friend about this (ruby) thing:

class Numeric (Math.methods - Module.methods - ["hypot", "ldexp"]).each do |method| define_method method do Math.send method, self end end end

And I showed him how one could do that easily in JavaScript:

Object.getOwnPropertyNames(Math).forEach(function (key) { if (typeof Math[key] === 'function') { Number.prototype[key]= function () { return Mathkey; }; } });

Of course this is a very specialized transfer in that you need to remap functions (that don't reference this) into a method that does. Essentially you are creating a wrapper method that calling a function passing the method's this value as an argument to the function all. This isn't like a normal object composition (eg "Object.extend" ) where you are just method references from one object to another. In this case you have to know how to make each function. You can do this because you know that every function valued property follow the same form and can use the same mapping pattern. i suspect that this is not a very common situations. Normally the methods you are transferring probably won't be this regular. or will have other issues (such a super reference) that would probably require you to use slightly different techniques such as Object.defineMethod.

Object.getOwnPropertyNames(Math).forEach(function (key) { if (typeof Math[key] === 'function') { Object.defineMethod(Number.prototype,key,function () { return Mathkey; }); } });

Bottom line, I'm not use that this really represents a very common scenario...

Then I thought, let's see how would that look like with arrows ?

But that would be wrong assume that arrows always lexically bind this.

Object.getOwnPropertyNames(Math).forEach((key) => { if (typeof Math[key] === 'function') Number.prototype[key]= () => Mathkey; });

To define a method you really need to use either a function definition (as in your original snippet) or alternatively a concise method in an object literal:

Object.getOwnPropertyNames(Math).forEach((key) => { if (typeof Math[key] === 'function') Number.prototype[key]= {m() {return Mathkey}.m; });

This suggests that we might benefit from defining Object.defineMethod in a way that leverages concise method syntax:

Object.getOwnPropertyNames(Math).forEach((key) => { if (typeof Math[key] === 'function') Object.defineMethod(Number.prototype,key, {method() {return Mathkey}); //if method arg is a non-functjon object use the value of its property named 'method' });

And it turns out that here, the outer/enclosing context this isn't the one you want/need. You'd need a dynamically bound this instead:

yes, but the root problem is trying use an arrow functions to define a method. Based upon these examples I'm inclined to think that Object.defineMethod should throw if the value it needs to install is a arrow function value.

Object.getOwnPropertyNames(Math).forEach((key) => { if (typeof Math[key] === 'function') Number.prototype[key]= (this) => Mathkey; });

and thus the this-in-the-parameters-list trick.

I don't think it's such a rare case: Inside a constructor function called with new, yes, this is most likely going to be the right this always, but when you are building objects with a factory (e.g. with a .create() method), the enclosing this usually isn't going to be the right one.

When you are building objects with a factory as you are describing you are presumably taking methods that were defined using an object literal or some other property method definition pattern:

let obj = mayFactory (arg) { return Object.extend({x:arg}, { method1() {...this...}, method2() {...this...}, ... /etc, }); };

The second argument to Object.extend might have been define remote but is likely still to be a template object with property dynamic this bound methods. I think the sort of this to argument remapping you show is actually pretty unusual.

# Claus Reinke (8 years ago)

I agree that leading |this| could be important for dynamic non-method use-cases, but those are relatively rare (let's not discount JQuery, but again, it could use long functions and survive). We could put leading-this-parameterization on the agenda for May, but we'll have to be careful not to lose consensus on arrows.

Other than the JQuery style misuse of this, what are the use cases? If you want to bind this, why wouldn't a method invocation on an objet be involved?

The ES array loops accept an optional this parameter to be used for the loop callback. The new strawman for data parallelism also passes this to its method callbacks.

Is there anything wrong with my getthis/fn wrappers as a workaround? We can't use 'this' as parameter name, and the wrapper adds a pair of parens. Anything else?

Claus

# Allen Wirfs-Brock (8 years ago)

On Apr 3, 2012, at 2:01 AM, Claus Reinke wrote:

I agree that leading |this| could be important for dynamic non-method use-cases, but those are relatively rare (let's not discount JQuery, but again, it could use long functions and survive). We could put leading-this-parameterization on the agenda for May, but we'll have to be careful not to lose consensus on arrows. Other than the JQuery style misuse of this, what are the use cases? If you want to bind this, why wouldn't a method invocation on an objet be involved?

The ES array loops accept an optional this parameter to be used for the loop callback.

It is up to the caller of the forEach to provide both the callback function and the optional this arg. So the caller has the option on both the kind of function passed and whether a this value is needed. Were today someone might code: I assume that the most common use of the optional argument today is something like this:

var obj = { id: genID(); log: function(value) {this.reporter.log(value+" from "+this.id}; state: populateArray(); logAll: function() { this.state.forEach( function(v) {this.log(v)}, this )} };

in other-words, it is available as an alternative to saying:

logAll: function() { var self = this; this.state.forEach(function(v) {self.log(v)}); }

(Note that if the bind that log was invoked on was anything other than the outer methods this then there would be no need for either of the above circumventions0

which is just an idiom to get around unwanted dynamic this binding in a method. With arrow functions you would just say:

logAll: function() {this.state.forEach(v-> ths.log(v))};

Arrow functions need to eliminate the need for such idioms that get around unwanted dynamic this bindings.

The new strawman for data parallelism also passes this to its method callbacks.

I need to look at the Rivertrail spec. but until I do, my guess, is that it is doing something similar that probably really isn't needed once arrow functions are available.

Is there anything wrong with my getthis/fn wrappers as a workaround? We can't use 'this' as parameter name, and the wrapper adds a pair of parens. Anything else?

No, there's nothing wrong with your wrappering, but I'm not sure why it would be needed. You code code the above as:

logAll: function() {this.state.forEach(fn((it,v)-> it.log(v)),this)};

but why would you? Particularly since you have to name the explicit initial this-like argument in the arrow something other than "this".

It seems like the main motivaton for a leading parameter named "this" in arrow functions is to use "this" to mean something different from the invocation target of the current method. Do that is a really bad idea as it just creates confusion about the the normal meaning of "this".

# Claus Reinke (8 years ago)

Other than the JQuery style misuse of this, what are the use cases? If you want to bind this, why wouldn't a method invocation on an objet be involved?

The ES array loops accept an optional this parameter to be used for the loop callback.

It is up to the caller of the forEach to provide both the callback function and the optional this arg. So the caller has the option on both the kind of function passed and whether a this value is needed.
.. in other-words, it is available as an alternative to saying:

logAll: function() { var self = this; this.state.forEach(function(v) {self.log(v)}); } .. Arrow functions need to eliminate the need for such idioms that get around unwanted dynamic this bindings.

Another way to look at these higher-order methods is that they split plain methods into framework (eg loop) and callbacks (eg loop body). Only the framework is directly attached to the object (eg Array), while the callbacks are passed in from the outside.

Passing the framework this to the callback brings framework and callback together again. One can write the callback as if it was part of the object method.

No, there's nothing wrong with your wrappering, but I'm not sure why it would be needed. You code code the above as:

logAll: function() {this.state.forEach(fn((it,v)-> it.log(v)),this)};

but why would you? Particularly since you have to name the explicit initial this-like argument in the arrow something other than "this".

I'm not saying that this is needed, only that we can account for this use case without changing arrow functions. And I was surprised that both pro and cons camps continued the discussion of recursive self and dynamic this naming as if no workaround was available.

To me, the ability to emulate the feature additions so closely in library functions suggests that some variation of fn and rec should go into the standard library instead of adding such features to arrow functions. But perhaps there are reasons for preferring the language features over the library functions?

Claus

# Brendan Eich (8 years ago)

Claus Reinke wrote:

And I was surprised that both pro and cons camps continued the discussion of recursive self and dynamic this naming as if no workaround was available.

I don't think anyone is really pushing hard for a dynamic-|this| form (say, ->) right now. Perhaps some want it but the thread here has helped

me, at least, stick to my YAGNI guns.

To me, the ability to emulate the feature additions so closely in library functions suggests that some variation of fn and rec should go into the standard library instead of adding such features to arrow functions.

Why wouldn't we add arrows too? There's a usability and an efficiency/easier-optimizability case for them even with fn and rec.

But perhaps there are reasons for preferring the language features over the library functions?

Your point about synthesizing dynamic-|this| given lexical-|this| forms is good. It seems to me having fn, rec, and => is therefore best. What

am I missing?

I do suspect people won't grok fn and rec, at least not with those names. They're very ML-ish or LISPy, not camelCaps JS-y.

# Claus Reinke (8 years ago)

To me, the ability to emulate the feature additions so closely in library functions suggests that some variation of fn and rec should go into the standard library instead of adding such features to arrow functions.

Why wouldn't we add arrows too? There's a usability and an efficiency/easier-optimizability case for them even with fn and rec.

I definitely want arrows, and I want them to be efficient enough that performance is not an obstacle to using them a lot (is mutability a problem for function call optimization?). fn and rec are just examples of how combining simple features can be as expressive as complex features.

Or do you mean adding self- and this-naming to arrows? If it doesn't hurt, I'm not against - I would just like to see a good case for how that would be an improvement.

But perhaps there are reasons for preferring the language features over the library functions?

Your point about synthesizing dynamic-|this| given lexical-|this| forms is good. It seems to me having fn, rec, and => is therefore best. What am I missing?

That is my current state of thinking, too.

I do suspect people won't grok fn and rec, at least not with those names. They're very ML-ish or LISPy, not camelCaps JS-y.

fn was a nod to the earlier "use fn" proposal, and rec seemed friendlier than y or fix:-) Also, both are short, rec suggests recursion and fn suggests short function. Yes, probably influenced by ML, but that isn't a bad precedent. But I'm not stuck on the names.

Claus

# Herby Vojčík (8 years ago)

Brendan Eich wrote:

Claus Reinke wrote:

And I was surprised that both pro and cons camps continued the discussion of recursive self and dynamic this naming as if no workaround was available.

I don't think anyone is really pushing hard for a dynamic-|this| form (say, ->) right now. Perhaps some want it but the thread here has helped me, at least, stick to my YAGNI guns.

Neither am I, but I'd like to see this-parameter in => to allow dynamic |this|.

# Claus Reinke (8 years ago)

Your point about synthesizing dynamic-|this| given lexical-|this| forms is good. It seems to me having fn, rec, and => is therefore best. What am I missing?

That is my current state of thinking, too.

Until I started thinking about performance:-( With current implementations, at least, using rec is impractical: not just slow but "too much" recursion. Which raises some questions:

  • what is the state of play/plans wrt implementing tail-call optimization?

  • what are the chances of JS implementations optimizing the overhead of fn and rec away? Overheads include

    • call-by-value requires eta-expansion (wrapping the recursive term to avoid runaway evaluation)

    • preference of multi-parameter lists over nested single parameters leads to use of apply/slice/concat

It is sad to see a language design question decided by implementation limitations, but until the questions above receive good answers (or someone comes up with better combinators;-), my proposed scheme is not practical.

Claus

# Angus Croll (8 years ago)

On Fri, Mar 30, 2012 at 4:46 AM, Felix Böhm <esdiscuss at feedic.com> wrote:

How about a "loose-bound" |this|, so that the function falls back to the bound |this| instead of the global scope when no other options are available (or null or undefined are passed to .apply/.bind/.call)?

I strongly support this proposal.

Any legacy utility (3rd party or otherwise) that assumes its function arguments are dynamically bound (a reasonable assumption as of ES 5.1) will be in trouble when passed hard-bound fat arrow functions. Here's a gist illustrating a simplified version of a functional mixin process and how it would break under the current fat arrow proposal.

gist.github.com/2266911

Yes we could use the long-form function instead, but it seems unnecessarily restrictive (not to mention confusing) that the much anticipated short-form syntax should be out-of-bounds whenever there is a remote possibility that the function may at some time need invoking with a different |this| value (and how can we even anticipate such a requirement? - especially if we are writing 3rd party libraries)

And yes there is an ES 5 precedent - Function::bind also makes a hard binding, but with bind there are no surprises, it is intentional and explicit - fat arrow lexical binding OTOH will probably be an unexpected side effect for those developers whose primary goal is to save key strokes.

Under Felix's proposal I'm assuming a soft-lexical binding would be overridable by call and apply (provided a valid context object is passed) or by the base reference of a method invocation. In other words if a |this| value is provided, use it, otherwise default to the lexical scope instead of the global scope.

I'm betting that covers most of the current |this| headaches we are trying to solve while keeping short-form syntax in play for those of us who value/rely on dynamic binding.

Angus

# Herby Vojčík (8 years ago)

Angus Croll wrote:

On Fri, Mar 30, 2012 at 4:46 AM, Felix Böhm <esdiscuss at feedic.com <mailto:esdiscuss at feedic.com>> wrote:

How about a "loose-bound" |this|, so that the function falls back to
the bound |this| instead of the global scope when no other options
are available (or `null` or `undefined` are passed to
`.apply/.bind/.call`)?

I strongly support this proposal.

No special cases for null or undefined, please.

# Angus Croll (8 years ago)

On Apr 8, 2012, at 4:00, Herby Vojčík <herby at mailbox.sk> wrote:

No special cases for null or undefined, please.

Fine. Then we should just default to lexical binding for standalone function calls - I'll stick my neck out and assert that it's the only area that needs fixing with respect to |this| binding

# Kevin Smith (8 years ago)

Any legacy utility (3rd party or otherwise) that assumes its function arguments are dynamically bound (a reasonable assumption as of ES 5.1) will be in trouble when passed hard-bound fat arrow functions. Here's a gist illustrating a simplified version of a functional mixin process and how it would break under the current fat arrow proposal.

gist.github.com/2266911

I don't see anything that is broken by arrow functions. You are attempting to use arrows for defining methods which is incorrect. This would be correct:

function withCircleUtils() {
    this.{
      area() { return this.radius * this.raduis * Math.PI; },
      diameter() { return this.radius + this.radius; }
    };
}

Do you see a problem with this construction?

# Angus Croll (8 years ago)

I don't see anything that is broken by arrow functions. You are attempting to use arrows for defining methods which is incorrect.

Sorry, I obfuscated unnecessarily by making the inner functions into arrows too. But the important one is the withCircleUtilsFat function which is not a method

This would have been clearer

var withCircleUtilsFat = () => { this.area = function() {return this.radius * this.radius * Math.PI}; this.diameter = function() {return this.radius + this.radius}; }

This would be correct:

function withCircleUtils() {
    this.{
      area() { return this.radius * this.raduis * Math.PI; },
      diameter() { return this.radius + this.radius; }
    };
}

Do you see a problem with this construction?

To reiterate: I am forced to use a long-form for withCircleUtils because we attached special meaning to the short-form. I think the criteria as to when to use short vs long-form will be unclear to many users and I can already see a future Good Parts equivalent suggesting "avoid arrows because the rules of when to use them are unnecessarily complex". Switching to soft lexical binding would remove these usage constraints. Indeed they would also allow arrow functions to define methods without resorting to the unwieldy initial 'this' argument proposal.

Bottom line: is the primary goal of arrow functions brevity or hard-lexical binding? If its the former (and even if it isn't a lot of dvelopers will percieve it as such) then we should be careful not to add usage caveats.

Angus

# Kevin Smith (8 years ago)

Which form has more brevity, then?

// This?
var withCircleUtilsFat = () => { ... };

// Or this?
function withCircleUtilsFat() { ... };

In any case, between object literal methods and arrow functions, I think you'll find that the vast majority of your function expressions will get a more concise syntax.

# Angus Croll (8 years ago)

Ha! nice catch :-)

My concern is with developers not knowing about the side effects of => and

therefore when to use it.

# manuelbarzi (a year ago)

taking this old discussion back a bit ( esdiscuss.org/topic/arrow-function-syntax-simplified), why shouldn't be a good idea to deprecate the use of function in pro of thin-arrow ->, being applicable in same cases (including named function)?

just a bit of code with more about proposals:

const GLOBAL_FACTOR = 2

const result = [1, 2, 3].map(function(value) { return GLOBAL_FACTOR * value
})

// PROPOSAL 1 - normal anonymous function (same as fat-arrow, but dynamic
binding, nothing much new here as from previous proposals):
// const result = [1, 2, 3].map(value -> GLOBAL_FACTOR * value)

function applyFactor(value) {
return GLOBAL_FACTOR * value
}

// PROPOSAL 2 - named function declaration (without 'function' keyword):
// applyFactor(value) -> GLOBAL_FACTOR * value

// referenced function (following PROPOSAL 1):
// const applyFactor = value -> GLOBAL_FACTOR * value

const sameResult = [1, 2, 3].map(applyFactor)

justification i read against this proposal is mainly that thin-arrow may bring "more confusion" and may "provide poor or no benefit" co-existing with fat-arrow. but having both may bring devs the chance to understand the differences in the learning process as any other feature. the only "big deal" would be to be aware of fix vs dynamic binding, which is something a dev must understand sooner or later, independently of syntax (it can be just explained with traditional function() {} and .bind() method).

on the other hand it would bring the chance to avoid over-using fat-arrow when binding it's not really necessary (which may "save" internal binding processing too), still keeping a simpler and shorter syntax as fat-arrows, avoiding the requirement of the keyword function.

# Isiah Meadows (a year ago)

Couple nita about your argunents:

  1. Most commonly used implementations don't close over more than what they have to. If this isn't used, it's not closed over. The addition of one more variable to check has so little overhead you won't gain anything.

  2. Deprecating anything in JS is hard in general. The little-used arguments.caller itself was a challenge.

Not TC39, but I strongly doubt this would have any traction for these + your additional justifications against.

# manuelbarzi (a year ago)

ok.

as little example, what if - for any case - you would explicitly require a function not to be auto-binded anymore, then in the current situation you would need to switch code from fat-arrow () => ... to bureaucratic function() { ... }. with thin-arrow you would just need to change symbol = by -, ending in just () -> .... i guess this simplicity may sound

trivial, but it would be aligned with and ease while coding, making es+ still thinking beyond, upon this situations and similar others (apart from the visible shortness and simplicity when writing () -> ... instead of function() { ... }).

let's bring a little example on expressing an operation to be applied on an object by itself:

const o = {
do(expression) {
expression.call(this)
    }
}

// cant apply or call on fat-arrow (as already binded to outer context)
//o.do(() => this.name = 'object') // won't work

// would then need to switch it to wordy `function` expression
o.do(function() { this.name = 'object' })

// but following PROPOSAL1, would just be (shorter and simpler):
// o.do(() -> this.name = 'object')

console.log(o.name)

needless to say, less characters, more compressed code.

# Ben Wiley (a year ago)

Purely from the standpoint of convincing people not to use fat arrows only because they look more cute or whatever, this would be a great addition to the language. The decision would then become which arrow is best for the use case, no longer some trivial aesthetic argument.

Le jeu. 25 oct. 2018 10 h 09, manuelbarzi <manuelbarzi at gmail.com> a écrit :

# manuelbarzi (a year ago)

not focussing on aesthetics, but on reduce of bureaucracy, which not by coincidence it's something fat-arrow functions already provide.

# Dan Aprahamian (a year ago)

IMHO this would be a cool feature. But when you consider that there are a limited number of operators available for future language features, it seems like this provides very little gain for consuming that operator.

# manuelbarzi (a year ago)

what about the simplification in coding, decrease of bureaucracy, reduction of characters, i.e. increase in code compression possibilities?

# Waldemar Horwat (a year ago)

On 10/25/2018 07:55 AM, manuelbarzi wrote:

not focussing on aesthetics, but on reduce of bureaucracy, which not by coincidence it's something fat-arrow functions already provide.

The committee has been swamped with numerous such syntax proposals. While any single one may be reasonable in isolation, each one adds significant complexity to the language, and the sum of them is too great (plus multiple proposals try to grab the same syntax for different purposes).

You will not be able to deprecate function, as that's just not web-compatible. Given the existing two syntaxes for defining functions (function and =>), creating a third one would just add complexity.

 Waldemar
# manuelbarzi (a year ago)

The committee has been swamped with numerous such syntax proposals. While any single one may be reasonable in isolation, each one adds significant complexity to the language, and the sum of them is too great (plus multiple proposals try to grab the same syntax for different purposes).

AFAIS this proposal does not collide with any other one pointing to same syntax. it's just one more push on same direction to the initial proposal (already linked before). plus adding the PROPOSAL 2 for named functions:

function applyFactor(value) {
return GLOBAL_FACTOR * value
}

// PROPOSAL 2 - named function declaration (without 'function' keyword):
// applyFactor(value) -> GLOBAL_FACTOR * value

You will not be able to deprecate function, as that's just not web-compatible.

"deprecation" could be progressive while keeping back-compat and encouraging users to switch to shorthand syntax of functions (and named functions) by means of thin-arrows. there's no intention to abruptly break anything.

Given the existing two syntaxes for defining functions (function and =>),

creating a third one would just add complexity.

would not that "complexity" be worth it, in favor of less bureaucracy and code compression?

why would just adding a shorthand syntax to functions with thin-arrows would be that "complexity drama"? because people would mix functions and thin-arrows? that's already a reality with code using functions and fat-arrows, and AFAIK nobody complains about it. the only diff here is just to be aware of when to auto-bind (=>) or not to auto-bind (->). don't

see any drama with that.

# Dan Aprahamian (a year ago)

Honestly, I doubt there is much benefit in compression as long as you are gzip-ing. In a typical application, the benefit will be on the order of bytes.

I don't see this as a simplification in coding. For me, it is a lot easier to see the difference between function and =>, while -> vs => is a

lot harder. I could see beginners getting very confused by this.

# Waldemar Horwat (a year ago)

On 10/25/2018 04:04 PM, manuelbarzi wrote:

The committee has been swamped with numerous such syntax proposals.  While any single one may be reasonable in isolation, each one adds significant complexity to the language, and the sum of them is too great (plus multiple proposals try to grab the same syntax for different purposes).

AFAIS this proposal does not collide with any other one pointing to same syntax.

I've seen informal proposals that do something else with ->.

Given the existing two syntaxes for defining functions (function and =>), creating a third one would just add complexity.

would not that "complexity" be worth it, in favor of less bureaucracy and code compression?

No.

why would just adding a shorthand syntax to functions with thin-arrows would be that "complexity drama"? because people would mix functions and thin-arrows? that's already a reality with code using functions and fat-arrows, and AFAIK nobody complains about it. the only diff here is just to be aware of when to auto-bind (=>) or not to auto-bind (->). don't see any drama with that.

That's actually the major source of the drama. The difference between => and -> would be subtle enough that it would be hard for casual users to keep track of which is which.

 Waldemar