Named Arrow Functions
On Tue, Aug 11, 2015 at 1:49 PM, Jacob Parker <jacobparker1992 at gmail.com> wrote:
I did look, but couldn’t find anything on named arrow functions were not included. I do sometimes find cases where I want recursion inside a class function definition, and still need access to
this
. Was it just seen as syntax bloat, or were there any complications to implementing it?Obviously a contrived example, but something like this (using do syntax too)
x.map(factorial(x) => do { if (x <= 1) { 1; } else { x * factorial(x - 1) } });
Probably not super-helpful in practice, but there's always the Y-combinator. ^_^
let Y = F => (x=>F(y=>(x(x))(y)))(x=>F(y=>(x(x))(y)));
x.map(Y(fact=>x=> do { if( x <= 1) { 1; } else { x * fact(x-1); } ));
Here, the syntax "Y(foo=>" indicates a "named" arrow function.
Woah, an actual application of Y combinator hahaha
In addition to being hard to parse in general, I don't think this would play very well with the async/await proposal tc39.github.io/ecmascript-asyncawait , which wants to have arrow functions like
async (x) => ...
Because we can't count on async as a keyword, your proposal would create an ambiguity.
What about a clojure like recur hidden variable binded to the bottom-level function?
x.map(factorial(x) => do { if (x <= 1) { 1; } else { x * recur(x - 1) } });
2015-08-11 21:26 GMT-03:00 Daniel Ehrenberg <dehrenberg at chromium.org>:
I assume you mean more like this (without factorial):
x.map((x) => do { if (x <= 1) { 1; } else { x * recur(x - 1) } });
One issue is that it's hard to add keywords to JavaScript at this point. If they're not from the tiny set of remaining reserved words (enum, anyone?), they can be users' identifiers, and have to be based contextually on some enclosing syntax, like yield is.
Another downside is that then, arrow functions have a distinct and less powerful method of recursing (e.g., nested functions won't be able to see the binding to the outer one).
Dan
Yeah., that's what I meant.
My proposal is not a keyword, but an hidden variable included at functions (e.g. arguments). Does arrow functions have any limitations about that?
2015-08-11 21:35 GMT-03:00 Daniel Ehrenberg <dehrenberg at chromium.org>:
Well, I found out arguments is actually a reserved word too haha
About that:
If they're not from the tiny set of remaining reserved words (enum, anyone?), they can be users' identifiers, and have to be based contextually on some enclosing syntax, like yield is.
That could be it, right? Since it would be only available at arrow functions(anon functions too?)
2015-08-11 21:42 GMT-03:00 Leonardo Wolter <leocwolter at gmail.com>:
x.map(factorial(x) => do { if (x <= 1) { 1; } else { x * factorial(x - 1) } });
This has been discussed over the years but there has been very little interest in making the grammar more complicated. After all, you can always just assign the arrow function to a locally-scoped variable. And as Daniel pointed out, this suggestion actually conflicts with async arrow functions.
My proposal is not a keyword, but an hidden variable included at functions (e.g. arguments). Does arrow functions have any limitations about that?
Yes. There are no special contextual keywords reserved within arrow functions. We've discussed the possibility of a "meta property" for this (e.g. "function.self") but there's little interest at present.
The real reason people need named arrow functions, the biggest use case is for event handlers.
let p = new Promise((resolve, reject) =>
setTimeout((x => () => x(x))(handler => {
onNotNeeded(() => clearTimeout(handler));
// `return` is to take advantage of TCO
return doSomethingAsync(err => {
if (err != null) return reject(err)
else return resolve();
});
}));
By the way, the way I created a self reference is a complete lambda calculus hack.
<deviation>
If you'd like your eyes to bleed, here's one that is purely out if lambdas. I couldn't help myself.
let p = new Promise((resolve, reject) =>
setTimeout((x => () => x(x))(h =>
x => y => y(x()))(
onNotNeeded(() => clearTimeout(h)))(
doSomethingAsync(e =>
if (err != null) return reject(err)
else return resolve();
});
}));
Sent this too early... Corrected inline.
On Tue, Aug 11, 2015, 21:56 Isiah Meadows <isiahmeadows at gmail.com> wrote:
The real reason people need named arrow functions, the biggest use case is for event handlers.
let p = new Promise((resolve, reject) =>
setTimeout((x => () => x(x))(handler => {
onNotNeeded(() => clearTimeout(handler));
// `return` is to take advantage of TCO
return doSomethingAsync(err => {
if (err != null) return reject(err)
else return resolve();
});
}));
By the way, the way I created a self reference is a complete lambda calculus hack.
<deviation>
If you'd like your eyes to bleed, here's one that is purely out if lambdas. I couldn't help myself.
let p = new Promise((resolve, reject) =>
setTimeout((x => () => x(x))(h =>
x => y => y(x()))(
onNotNeeded(() => clearTimeout(h)))(
doSomethingAsync(e =>
e
!= null
?
reject(err)
:
resolve()
)))
);
On Tue, Aug 11, 2015, 20:45 Leonardo Wolter <leocwolter at gmail.com> wrote:
Well, I found out arguments is actually a reserved word too haha
About that:
If they're not from the tiny set of remaining reserved words (enum, anyone?), they can be users' identifiers, and have to be based contextually on some enclosing syntax, like yield is.
That could be it, right? Since it would be only available at arrow functions(anon functions too?)
2015-08-11 21:42 GMT-03:00 Leonardo Wolter <leocwolter at gmail.com>:
Yeah., that's what I meant.
My proposal is not a keyword, but an hidden variable included at functions (e.g. arguments).
Does arrow functions have any limitations about that?
2015-08-11 21:35 GMT-03:00 Daniel Ehrenberg <dehrenberg at chromium.org>:
I assume you mean more like this (without factorial):
x.map((x) => do { if (x <= 1) { 1; } else { x * recur(x - 1) } });
One issue is that it's hard to add keywords to JavaScript at this point. If they're not from the tiny set of remaining reserved words (enum, anyone?), they can be users' identifiers, and have to be based contextually on some enclosing syntax, like yield is.
Another downside is that then, arrow functions have a distinct and less powerful method of recursing (e.g., nested functions won't be able to see the binding to the outer one).
Dan
On Tue, Aug 11, 2015 at 5:30 PM, Leonardo Wolter <leocwolter at gmail.com>
wrote:
What about a clojure like recur hidden variable binded to the bottom-level function?
x.map(factorial(x) => do { if (x <= 1) { 1; } else { x * recur(x - 1) } });
2015-08-11 21:26 GMT-03:00 Daniel Ehrenberg <dehrenberg at chromium.org>:
In addition to being hard to parse in general, I don't think this would play very well with the async/await proposal tc39.github.io/ecmascript-asyncawait , which wants to have arrow functions like
async (x) => ...
Because we can't count on async as a keyword, your proposal would create an ambiguity.
On Tue, Aug 11, 2015 at 1:49 PM, Jacob Parker <jacobparker1992 at gmail.com> wrote:
I did look, but couldn’t find anything on named arrow functions were
not
included. I do sometimes find cases where I want recursion inside a
class
function definition, and still need access to
this
. Was it just seen
as
And as Kevin said, it has been mentioned before (with event handlers and timeouts as the initial driving force).
Ups, I answered only to Jacob but I think this is a real simple solution:
var factorial;
x.map(factorial = x => x < 1 ? 1 : x * factorial(x-1));
Or simply:
var factorial = x => x < 1 ? 1 : x * factorial(x-1);
x.map(factorial);
As you said, this is ocassionally needed. And for event handlers:
var once = evt => { button.onclick = null; onClick(evt) };
button.onclick = once;
And yes, this solution was already provided: esdiscuss.org/topic/self-recursion-and-arrow-functions#content
For use cases that require named Functions (e.g. recursion), surely it's not a such a big deal to either assign an Array Function to a variable first, or use the good old trusty named Function expression or Function statement.
var recurseExample = () => { recurseExample(); }
var recurseExample = function recurseExample () { recurseExample(); }
function recurseExample () { recurseExample(); }
I wonder if it's even a good idea to use Arrow Functions in places that do
not benefit from the new this
behaviour? Just because code takes up fewer
characters does not necessarily mean it is easier to understand.
On 12 August 2015 at 02:56, Isiah Meadows <isiahmeadows at gmail.com> wrote:
let p = new Promise((resolve, reject) =>
setTimeout((x => () => x(x))(handler => {
onNotNeeded(() => clearTimeout(handler));
// `return` is to take advantage of TCO
return doSomethingAsync(err => {
if (err != null) return reject(err)
else return resolve();
});
}));
This doesn't work as the function passed to clearTimeout does not === the function passed to setTimeout.
In fact, they're not even behaviorally equal as the function passed to setTimeout is expecting no parameters and the function passed to clearTimeout is expecting one parameter - i.e. this is not even correct in lambda calculus.
A lambda-calculus-correct version could be:
setTimeout((x=>(y=>()=>x(y(y)))(y=>()=>x(y(y))))(handler => {...}));
But this would still suffer from the object identity problem mentioned above. A final JS-correct version could be:
setTimeout((x => {const y = () => x(y); return y;})(handler => {...}));
Nick
AFAIK, this wont work because what clearTimeout() is actually expecting is the id returned by setTimeout(). El 12/8/2015 16:00, "Nick Krempel" <ndkrempel at google.com> escribió:
This was assuming an API like addEventListener/removeEventListener, not the standard DOM setTimeout/clearTimeout, sorry for the confusion.
Oops... Used to Node world. I didn't really test it, since I replied by phone.
I did look, but couldn’t find anything on named arrow functions were not included. I do sometimes find cases where I want recursion inside a class function definition, and still need access to
this
. Was it just seen as syntax bloat, or were there any complications to implementing it?Obviously a contrived example, but something like this (using do syntax too)