Can I use ES6's arrow function syntax with generators? (arrow notation)

JavascriptEcmascript 6SyntaxGeneratorArrow Functions

Javascript Problem Overview


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.)

Javascript Solutions


Solution 1 - Javascript

> 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 "}"

Solution 2 - Javascript

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, or new.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, bind return in the Block body case so it returns from the immediately enclosing arrow function, and preclude break and continue 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.

Solution 3 - Javascript

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.

Solution 4 - Javascript

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.

Solution 5 - Javascript

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.

Solution 6 - Javascript

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.

Solution 7 - Javascript

There is a nice workaround with redux-saga

import { call, all } from 'redux-saga/effects';

function* gen() {
   yield all([].map(() => {
      return call(....);
   }));
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAshley CoolmanView Question on Stackoverflow
Solution 1 - Javascriptuser663031View Answer on Stackoverflow
Solution 2 - JavascriptCoderPiView Answer on Stackoverflow
Solution 3 - Javascriptmonk-timeView Answer on Stackoverflow
Solution 4 - JavascriptBhojendra RauniyarView Answer on Stackoverflow
Solution 5 - JavascriptGourav MakhijaView Answer on Stackoverflow
Solution 6 - Javascriptcoolreader18View Answer on Stackoverflow
Solution 7 - JavascriptJulius BaltrušaitisView Answer on Stackoverflow