That is, how do I express
function *(next) {}
with arrow syntax? I've tried all the combinations I could think of, and I can't find any documentation on it.
(I am currently using Node.js v0.11.14.)
8 Answers 8
Can I use ES6's arrow function syntax with generators?
You can't. Sorry.
According to MDN
The
function*
statement (function
keyword followed by an asterisk) defines a generator function.
From a spec document (my emphasis):
The function syntax is extended to add an optional
*
token:
FunctionDeclaration: "function" "*"? Identifier "(" FormalParameterList? ")"
"{" FunctionBody "}"
-
310Feels like a design flaw to me.Jonathon– Jonathon04/17/2015 09:05:31Commented Apr 17, 2015 at 9:05
-
36@Jonathon: No. Arrow functions are supposed to be light-weight (and don't have a
.prototype
for example) and often one-liners, while generators are pretty much the opposite.Bergi– Bergi04/17/2015 13:26:02Commented Apr 17, 2015 at 13:26 -
68I have already run across a few scenarios where a generator I was playing with needed access to the previous
this
, and had to write thelet self = this
hack to get access to it inside the generator. The lexical scope + arrow syntax would have been nice. Unfortunate, but not exactly the end of the world.dvlsg– dvlsg04/17/2015 23:44:48Commented Apr 17, 2015 at 23:44 -
72@Bergi the reasoning behind arrow functions is a lot more complicated than that. It's not really about brevity. Arrow functions needn't be lightweight – it's true there's an optional single-statement body syntax, but so what. Many people use arrows for all function definitions except class methods, and demote the
function
keyword to being a 'bad part' of the language. There are good reasons to do this. For these people, the lack of arrow generators is an annoying inconsistency.callum– callum04/07/2017 17:15:46Commented Apr 7, 2017 at 17:15 -
6@callum I did mean lightweight in terms of instance creation and call overhead, not syntax. Not sure what you think the reasoning behind them was. And no, I don't see any good reasons to use non-declarative arrow function expressions over
function
declarations.Bergi– Bergi04/08/2017 07:31:38Commented Apr 8, 2017 at 7:31
The difference between Inline-functions and Arrow-functions
First of all Arrow-functions () => {}
are not made to replace Inline-functions function(){}
and they are different.
Inline-Functions are simply Functions, so the question is what the difference between Arrow-functions and Inline-Functions are.
An arrow function expression (also known as arrow function) has a shorter syntax compared to function expressions and does not bind its own
this
,arguments
,super
, ornew.target
). Arrow functions are always anonymous.
Some more quick details here
Why Arrow-function can not be used as generators
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions
Use of the yield keyword
The yield keyword may not be used in an arrow function's body (except when permitted within functions further nested within it). As a consequence, arrow functions cannot be used as generators.
Note that generators without yield
don't make sense.
Why Arrow-function can not use yield
http://tc39wiki.calculist.org/es6/arrow-functions/
Arrow functions bind
this
lexically, bindreturn
in the Block body case so it returns from the immediately enclosing arrow function, and precludebreak
andcontinue
from referencing statements outside the immediately enclosing arrow function.The Identifier primary expression
arguments
may not be used in an arrow function's body (whether expression or block form).Likewise,
yield
may not be used in an arrow function's body. Arrows cannot be generators and we do not want deep continuations.
Yield in an Arrow-Function will throw Semantic Error: http://www.ecma-international.org/
In the End the reason is in the deep complexity in the implementation of ECMA6. C# does not allow this as well for somewhat similar reasons.
-
109I'm trying to figure out why
*() => { yield bla; }
isn't ok, butasync () => { await bla; }
is...Lee Benson– Lee Benson09/20/2016 13:17:38Commented Sep 20, 2016 at 13:17 -
11@CodeiSir, Re "and we do not want deep continuations", lousy excuses.Pacerier– Pacerier03/20/2017 10:06:35Commented Mar 20, 2017 at 10:06
-
45Your argument is cyclical. You say that arrow functions can't be generators because they can't have the yield keyword in them. But they can't have the yield keyword, because they can't be generators: "Arrows cannot be generators and we do not want deep continuations."Thayne– Thayne04/18/2019 16:38:41Commented Apr 18, 2019 at 16:38
-
21That's circular reasoning; An arrow function can't be a generator, because it's not allowed to have a
yield
statement, and it can't have ayield
statement, because it's not allowed to be a generator. 🤨Sapphire_Brick– Sapphire_Brick06/10/2020 22:36:51Commented Jun 10, 2020 at 22:36 -
17This doesn’t really answer why. Yes it's true, an arrow function can't be a generator because it isn't allowed to contain
yield
, but there's no reason why the syntax could have been designed to allow it. What is the reason the designers didn't want arrow functions to be able to be generators?chharvey– chharvey10/14/2020 03:29:52Commented Oct 14, 2020 at 3:29
In addition to the discussion on esdiscuss.org and the Ecma TC39 committee ES6 meeting notes from November 2013 mentioned above, generator arrows were revisited in two September 2016 ES7 meetings [1] [2]. After a discussion about pros and cons of various syntax (mainly =*>
and =>*
) and a lack of justifications and use cases for this feature, they came to the conclusion that:
- There is some interest from the committee, but concern that the feature does not pull its weight for adding a new piece of syntax
- Plan to revisit on Day 3 to see if we can get
=>*
to stage 0 at least, as part of [Domenic Denicola]'s async iteration proposal
The proposal for generator arrows was moved to Stage 1 with Brendan Eich and Domenic Denicola as champions. Asynchronous iteration mentioned above was finished and implemented in 2018.
In Oct 2019 an official repo by Sergey Rubanov appeared with more discussion about syntax and other details.
Right now you can not, but in future you might be because TC39 release proposal for same in october 2019, which is in stage 1.
I was also having the same question and came here. After reading the posts and comments, I felt using generator in an arrow function seems to be vague:
const generator = () => 2*3; // * implies multiplication
// so, this would be a confusing
const generator = () =>* something; // err, multiplying?
const generator = () =*> ... // err, ^^
const generator = ()*=> ... // err, *=3, still multiplying?
const generator=*()=> ... // err, ^^
const generator = *param => ... //err, "param" is not fixed word
This is what may be the big reason they didn't implement generator in relation with arrow function.
But, if I were one of them, I could have thought like this:
const generator = gen param => ... // hmm, gen indicates a generator
const generator = gen () => ... // ^^
This feels just like we have asynchronous function:
const asyncFunction = async () => ... // pretty cool
Because, with normal function the async keyword exist, so arrow function is utilizing it - async () =>
is likely to seem async function()
.
But, there's no keyword like gen
or generator
and alas arrow function is not using it.
To conclude:
Even if they wish to implement the generator in the arrow function, I think they need to re-think about generator syntax in core js:
generator function myfunc() {}
// rather than
function* myfunc() {} // or, function *myfunc() {}
And this will be a big blunder. So, keeping arrow function out from the generator, is pretty cool.
Following @Bergi comment:
No. Arrow functions are supposed to be light-weight (and don't have a .prototype for example) and often one-liners, while generators are pretty much the opposite.
I will say that generator purpose to use is run-stop-run and so I don't think we need to care about prototype, lexical this, etc.
-
The question is an invitation to explain the status quo, not submit proposals how it may be changed.dumbass– dumbass11/22/2024 11:20:54Commented Nov 22, 2024 at 11:20
You can, but not really in a nice way. It's not shorter and does not look that pretty. Check this out:
function* iterable(arg) {
yield* [];
}
async function* asyncIterable(arg) {
yield* [];
}
const arrowIterable = arg => {
return {
*[Symbol.iterator]() {
yield* [];
},
};
};
const arrowAsyncIterable = arg => {
return {
async *[Symbol.asyncIterator]() {
yield* [];
},
};
};
This works because an iterable is basically an object with the Symbol.iterator
or Symbol.asyncIterator
set to an iterator. A generator is an iterator!
Enjoy!
-
Those are not equivalent:
typeof iterable().next !== typeof arrowIterable().next
.dumbass– dumbass11/23/2024 10:48:00Commented Nov 23, 2024 at 10:48 -
I know that this is very late, but another possible reason could be syntax. maybe (*() => {})
works, but what about (9 ** () => {})
? Is that 9 to the power of an arrow function, returning NaN
, or is it 9 times a generator arrow function, also returning NaN
? It could be done with some alternative syntax, like =>*
as mentioned by another answer here, but maybe there was a desire to preserve the consistency of the generator function syntax (eg. function* () {}
and { *genMethod() {} }
) when it was being implemented. Not too much of an excuse, but a reason for it.
-
The question is an invitation to explain the status quo, not submit proposals how it may be changed.dumbass– dumbass11/22/2024 11:22:38Commented Nov 22, 2024 at 11:22
There is a nice workaround with redux-saga
import { call, all } from 'redux-saga/effects';
function* gen() {
yield all([].map(() => {
return call(....);
}));
}
-
5
Explore related questions
See similar questions with these tags.
function*
statement (function keyword followed by an asterisk) defines a generator function."param*=>{ }
to do?function(){}
is not doing the same as()=>{}
?