'function *' is not mandatory

# Yuichi Nishiwaki (11 years ago)

I just found a post that the current generator syntax (function *) seems have decided in:

esdiscuss/2011-July/015799

According to the post, the biggest reason the star syntax is adopted for now is that you cannot write empty generators with star-less functions in a consistent simple way. But the situation has changed, and in the current spec (rev 17) yield* is now capable of taking any kind of iterator, so you can make empty generators just like

function * () {
    yield * [];
}

This looks enough good and simple at least to me. And I wonder if even now generators still need to be declared with 'star's. What are the advantages of 'star'ed generators rather than 'star'-lesses? If not exist, shouldn't it be removed (for the simplicity)?

# Brendan Eich (11 years ago)

The empty-body basis case is one reason. A stronger reason is that yield is not a reserved identifier, and it is used in existing content, so function* allows contextual reservation without breaking backward compatibility.

Another reason is to clue readers in early, when reading in source order, that this function is a generator, in the case where yield usage in the function's body is somewhat hard to see at a glance.

# Oliver Hunt (11 years ago)

The reason for the * is substantially (IIRC) to make it possible for an engine to help prevent developers from unintentionally creating a generator function, and to make it possible for someone attempting to use a function to identify immediately whether it is a generator or a regular function.

# Yuichi Nishiwaki (11 years ago)

ES5 specifies yield as a reserved keyword, right? So there should be no need to make it contextual.

# Brendan Eich (11 years ago)

Yuichi Nishiwaki <mailto:yuichi.nishiwaki at gmail.com> August 31, 2013 12:45 PM

ES5 specifies yield as a reserved keyword, right?

Wrong, only ES5 strict reserved yield.

So there should be no need to make it contextual.

There is; when we first tried reserving yield in 2006, we had to put it behind opt-in versioning because content used yield as an unqualified identifier. IIRC it's still used.

Backward compatibility is what it is. "use strict"; in ES5 was an opt-in, so not widely adopted enough (i.e., universally adopted) to help.

# Yuichi Nishiwaki (11 years ago)

I can't get the point, why you need to know if the function is a generator or not at a glance?

  1. Forcing users to mark the function as a generator is only a duplication. It basically doesn't have any meaning other than double-checking, and fundamental risk for the unintentional creation is still not removed.
  2. Even if you know the function is a generator in early, you still need to read the entire source code to get the information about what the generator yields and when it stops.
# Brendan Eich (11 years ago)

Let's not go in circles -- the primary reason for function* is because yield is not reserved in JS and is used by web content as a plain identifier. It is a low-precedence unary prefix operator, so cannot be contextually reserved by a grammatical restriction as "module" can. It needs opt-in syntax.

Separately, some on TC39 want a flag on the function, in the head syntax, to alert readers to the generator. That's a secondary reason, independent and not as strong in my view.

There's nothing to "get" or "not get" about backward compatbility. It just "is". :-|

# Yuichi Nishiwaki (11 years ago)

OK, right. I understand my first propose does not work. :-| So one more question is how about making '*' optional in strict mode? (Should I separate the topic to another?)

# Mark S. Miller (11 years ago)

I am one of those on TC39 that want the visible flag. Since, in my view, the only non-mistaken need to preserve sloppy mode is as an ES3 compatibility mode and ES3 has no generators, I consider this flagging issue to be the important one. Yes, you have to read the function to know what it generates. But even before you've figured that out, your whole effort to read the function is different once you know you're reading a generator function. Better to know it early.

Code is read much more than it is written -- at least code that matters.

# Brendan Eich (11 years ago)

Mark's reply helps, but I want to add that we are not making gratuitous differences between strict and non-strict mode. Modes are bad, one is more than enough. Further speciation in later editions just makes more. Just say no, write that * after function, and get on with life :-).

# Claus Reinke (11 years ago)

I am one of those on TC39 that want the visible flag. Since, in my view, the only non-mistaken need to preserve sloppy mode is as an ES3 compatibility mode and ES3 has no generators, I consider this flagging issue to be the important one. Yes, you have to read the function to know what it generates. But even before you've figured that out, your whole effort to read the function is different once you know you're reading a generator function. Better to know it early.

But that is a semantic property - you can't force it into syntax.

Consider this code:

// run with node --harmony
function* gen() { yield 1 }
function f(g) { return g() }
console.log( f(gen).next() ); // { value: 1, done: false }

You can't see by looking at f that it can return an iterator. And fs parameter and return value could even vary dynamically.

I could imagine a type system for this, which would be nice (just as it would be nice to have a type system telling you whether a callback-taking function uses the callback async, sync, or both). Then your IDE could tell you (an approximation of) what you're dealing with, providing verified API documentation. But I don't see how to do that with syntactic tools only.

Code is read much more than it is written -- at least code that matters.

For this reason, I would still suggest to separate generators from function - there is nothing function-specific about generators (apart from generator implementations using stack frames, perhaps), so I find it confusing to mix up these two concepts. It also keeps us from using arrow functions freely with generators.

I did suggest using something like do* { yield 1 } as generator syntax (ie, do*{} would be an expression denoting an iterable, and yield could only appear in do*{}). It still has the syntactic flag, but it separates functions and generators. We could then recombine the two as needed, without complicating the function-related specification machinery:

let gen = v => do* { yield v };
gen(1).next()    // { value: 1, done: false }
# Yuichi Nishiwaki (11 years ago)

I get the point. Indeed. Modes are a kind of magic...

Regarding the secondary reason: I don't understand the "difference" well, could you explain in detail? You know, all other languages that are dynamically typed and have generators, such as python, lua, and even JavaScript 1.8 don't distinguish two kinds of the functions. I guess this directly means that there isn't something different as you said (because they all have more or less made successful). And in my personal view, yield is something that can be generalized together with return, like

  • return: discards the succeeding partial continuation there
  • yield: preserve the succeeding partial continuation there

It is very clear in a sense, I believe. So my guess is that the strangeness yields have is a mater of getting used to, and that it is much more natural to treat two of them as a same thing.

# Brendan Eich (11 years ago)

Generators are a kind of factory function. When you call a generator, you get an iterator with a bit of extra protocol (.throw as well as .next).

No big deal, lots of API contracts are implemented by functions, you say -- why does this one deserve special head syntax. 'return' can be hard to spot, just as 'yield' could be hidden, in a large body -- and return of a certain-shaped object as part of an API contract could be even harder to discern.

In general, you have a point. Languages such as Scheme or Racket enable their users customize built-in syntax all the time to express contracts better, even with static syntactic checking using macros. Even macro-less languages may have decorators (CoffeeScript's syntax cleverly enables decorators "for free").

You might think of function* as decorator syntax. It's important, given the 'yield' backward compatibility issue, not to make the syntax too heavyweight. One character is as minimal as we can get.

But now I'm just shoring up the argument based on compatibility. You'll have to get Mark or someone else to help you understand their particular argument that the function head needs decoration to alert the reader to the possible (not required) presence of yield in the body.

Note also the empty-body basis case -- that's a good argument for function* independent from the backward-compatibility and good-for-readers arguments.

# Brian Kardell (11 years ago)

Fwiw, just bikesheddingly speaking I actually prefer the *.

# Brendan Eich (11 years ago)

Brian Kardell wrote:

Fwiw, just bikesheddingly speaking I actually prefer the *.

Let's review. Three reasons for function* syntax:

  1. Opt-in required for backward-incompatible definition of 'yield' as low-precedence unary prefix operator.

  2. Zero-yield (no yield in body) basis case, useful for delegation via yield* from another generator.

  3. Decorator to alert the reader that the body contains yield (ignoring 2 for a moment) reason.

You are "bikesheddingly" supporting 3, I take it. Can you say more about why you want a decorator for human readers? Again ignoring 2, which makes the case based on what the JS engine must see, a more "objective" criterion in this case (and, in a different light, in case 1).

# Mark S. Miller (11 years ago)

On Sat, Aug 31, 2013 at 2:12 PM, Yuichi Nishiwaki <yuichi.nishiwaki at gmail.com> wrote:

I get the point. Indeed. Modes are a kind of magic...

Regarding the secondary reason: I don't understand the "difference" well, could you explain in detail?

function f(....) {
  // .... code sequence 1

  // .... balanced code sequence 2

  // .... code sequence 3
}

Without looking at f's parameters, code sequence 1, or code sequence 3, the reader knows that code sequence 2 will execute some number of times, perhaps 0, only during the turn in which f is called and before f returns. Once f's caller gets control again, code sequence 2 will no longer ever execute as part of that call to f. The only contextual knowledge the reader needs in order to know this is that there are no intermediate function definitions within f wrapping code sequence 2 -- i.e., that code sequence 2 is code of the function f itself, as opposed to code of a function within function a. It suffices to check that there are no unbalanced function definition starts in code sequence 1. Beyond this "is it wrapped in a function" question, the reader doesn't even care if code sequence 1 starts a control structure wrapping code sequence 2, that is closed in code sequence 3.

If the header says function*, then the reader knows that they do not know all this, and a more careful read is needed to understand when code sequence 2 might execute as part of a given call to f after f's caller resumes.

See erights.org/data/irrelevance.html on the need to do partial reasoning about code fragments. I find it frustrating that there so little computer science devoted to the cognitive load required of such partial program understanding tasks. This properly should be part of the study of "notation as user interface".

# Yuichi Nishiwaki (11 years ago)

2013/9/1 Brendan Eich <brendan at mozilla.com>:

Generators are a kind of factory function. When you call a generator, you get an iterator with a bit of extra protocol (.throw as well as .next).

No big deal, lots of API contracts are implemented by functions, you say -- why does this one deserve special head syntax. 'return' can be hard to spot, just as 'yield' could be hidden, in a large body -- and return of a certain-shaped object as part of an API contract could be even harder to discern.

Well, you don't answer the question, why do you think your APIs are truly better then others? In other words, why do you think there is a kind of difference between a normal function and the factory function, and think that the latter is evil? I don't see the reason why you think the latter can be harder to find.

In general, you have a point. Languages such as Scheme or Racket enable their users customize built-in syntax all the time to express contracts better, even with static syntactic checking using macros. Even macro-less languages may have decorators (CoffeeScript's syntax cleverly enables decorators "for free").

I'm not talking about languages with macros. Almost all macro-less languages could decide to have syntactic decorators when newly introducing generators to themselves, but in fact they did not.

You might think of function* as decorator syntax. It's important, given the 'yield' backward compatibility issue, not to make the syntax too heavyweight. One character is as minimal as we can get.

But now I'm just shoring up the argument based on compatibility. You'll have to get Mark or someone else to help you understand their particular argument that the function head needs decoration to alert the reader to the possible (not required) presence of yield in the body.

Sure, I want :)

# Brian Kardell (11 years ago)

On Aug 31, 2013 6:20 PM, "Brendan Eich" <brendan at mozilla.com> wrote:

You are "bikesheddingly" supporting 3, I take it. Can you say more about why you want a decorator for human readers? Again ignoring 2, which makes the case based on what the JS engine must see, a more "objective" criterion in this case (and, in a different light, in case 1).

Yes. I know its not especially useful and i debated sitting it out (as i often do on this list) - i think #1 stands on it own, but I felt that there was some debate about the value of #3 which isn't for compatibility or even function but for developers, and perhaps it might be useful to say that given the choice between * and none, I'd prefer the visual queue that tells me its different with an easy scan because...It's bikesheddy - i know but I thought it worth saying that as one of those devs I think it has value. So if we can get 1 and 3 with a single char... Win.

# Yuichi Nishiwaki (11 years ago)

You say the things get worse because introducing yields causes a probem that another parameter -- when to call a certain code block -- might be added at the time when readung the code, but I don't agree. There is already a parameter for code reading: how many times the code will be executed (or in short, whether the code is run, 0 or 1).

Whenever you read the code you have to read until you come across the first, assumed to be executed when passed the arguments you want do at the time, return statement to know what will happen when you invoke the function, and this is the same case to yields. You need to take care of the timing only after that.

# Allen Wirfs-Brock (11 years ago)

On Aug 31, 2013, at 3:19 PM, Brendan Eich wrote:

Brian Kardell wrote:

Fwiw, just bikesheddingly speaking I actually prefer the *.

Let's review. Three reasons for function* syntax:

  1. Opt-in required for backward-incompatible definition of 'yield' as low-precedence unary prefix operator.

  2. Zero-yield (no yield in body) basis case, useful for delegation via yield* from another generator.

  3. Decorator to alert the reader that the body contains yield (ignoring 2 for a moment) reason.

You are "bikesheddingly" supporting 3, I take it. Can you say more about why you want a decorator for human readers? Again ignoring 2, which makes the case based on what the JS engine must see, a more "objective" criterion in this case (and, in a different light, in case 1).

I think there is more to #3. The body of a GeneratorFunction has quite different semantics than that of a regular function. This is particularly clear when you think about GFs as actually being constructors/factories. The body of a normal constructor/factory defines what happens before a new instance object is returned to a caller. The body of a GeneratorFunction defines the future behavior of the instance object that is returned to the caller. A regular Function's body is evaluated before it's call returns. A GeneratorFunction's body is evaluated sometime after its call returns. This is a critical difference that must to known to a code reader in order to understand any code that includes a GeneratorFunction definition and is more that sufficient to warrant the * sigil. Personally, I would prefer an even stronger marker, such as a different keyword, but * is adequate. Programming language need to be designed for people. Inferring which functions are GeneratorFunction by the presences of yield may be fine for compilers but it isn't good enough for human readers or writiers.

# Brendan Eich (11 years ago)

Brian Kardell <mailto:bkardell at gmail.com> August 31, 2013 4:21 PM

Yes. I know its not especially useful

No, thanks for commenting.

and i debated sitting it out (as i often do on this list) - i think #1 stands on it own, but I felt that there was some debate about the value of #3 which isn't for compatibility or even function but for developers, and perhaps it might be useful to say that given the choice between * and none, I'd prefer the visual queue

("cue" ;-)

that tells me its different with an easy scan because...It's bikesheddy - i know but I thought it worth saying that as one of those devs I think it has value. So if we can get 1 and 3 with a single char... Win.

Mark makes the case for partial program understanding, so it's not just bikeshedding. I sense people are put off by bikeshedding and sometimes knee-jerk away from anything resembling it just because syntax is involved, but there's more to most issues here than the color of the paint on the bikeshed. And of course, once we have the power plant in front of the bikeshed operating well, it's fine to argue about the best color ;-).

# Brendan Eich (11 years ago)

I hope you agree we are beating a dead horse, given my reasons #1 and 2 require function* -- just checking.

Yuichi Nishiwaki wrote:

2013/9/1 Brendan Eich<brendan at mozilla.com>:

Generators are a kind of factory function. When you call a generator, you get an iterator with a bit of extra protocol (.throw as well as .next).

No big deal, lots of API contracts are implemented by functions, you say -- why does this one deserve special head syntax. 'return' can be hard to spot, just as 'yield' could be hidden, in a large body -- and return of a certain-shaped object as part of an API contract could be even harder to discern.

Well, you don't answer the question, why do you thinkyour APIs are truly better then others?

I never wrote "better" about API. The issue is whether, ignoring reasons 1&2, we help readers by flagging generator functions in their head syntax. We do, TC39 has agreed, although some of us feel more strongly about this than others (look for my next message, in reply to Allen, where I take your side).

So the issue is not "better API deserves syntax", and my point about macros was meant to cite languages where the playing field between standards bodies and language users who can write macros is leveled, precisely because all syntax above the special forms is defined using macros.

In other words, built-in function* syntax (again ignoring prioritized reasons 1&2) in JS is not a judgment about "better", only "necessary because predefined". If we could use macros, we would -- and then so could other people specifying APIs, developing specific factory function contracts, etc.

I hope this makes sense.

In other words, why do you think there is a kind of difference between a normal function and the factory function, and think that the latter isevil?

Never wrote "evil". Remember, I'm the champion of generators since 2006 in ES4, when we prototyped them in SpiderMonkey. All without function*, BTW.

I don't see the reason why you think the latter can be harder to find.

(Stay tuned for my next message.)

In general, you have a point. Languages such as Scheme or Racket enable their users customize built-in syntax all the time to express contracts better, even with static syntactic checking using macros. Even macro-less languages may have decorators (CoffeeScript's syntax cleverly enables decorators "for free").

I'm not talking about languages with macros. Almost all macro-less languages could decide to have syntactic decorators when newly introducing generators to themselves, but in fact they did not.

True, and that is worth considering when doubting reason #3. I agree with you there.

# Brendan Eich (11 years ago)

Allen Wirfs-Brock wrote:

I think there is more to #3. The body of a GeneratorFunction has quite different semantics than that of a regular function.

Not necessarily. See Yuichi's reply to Mark.

This is particularly clear when you think about GFs as actually being constructors/factories.

Lots of constructors/factories out there. An essential (see Aristotle) argument for why function* for generator syntax (ignoring trumping reasons 1&2) must say why this particular factory needs special (a la function*) head syntax.

The body of a normal constructor/factory defines what happens before a new instance object is returned to a caller. The body of a GeneratorFunction defines the future behavior of the instance object that is returned to the caller.

Functions may diverge (iloop/recurse-to-death). They may contain dead code. Yuichi's right, there has to be more to Mark's partial program understanding than just whether top-level (balanced) code runs at all, if one is making an essential distinction between generator functions and other functions.

A regular Function's body is evaluated before its call returns.

Yes, generators have an implicit yield; at the top. Now you have hit an essential difference with other functions.

A GeneratorFunction's body is evaluated sometime after its call returns.

This is ill-stated. You mean a continuation of a yield in its body is evaluated, not the whole body (re-)evaluated.

Of course, there may be no yield, or the yield may not be reached. Yuichi pointed out similarity with return.

This is a critical difference that must to known to a code reader in order to understand any code that includes a GeneratorFunction definition and is more that sufficient to warrant the * sigil.

TC39ers agree but it's good we have reasons 1&2, because consensus on 3 alone is fragile. Especially with lousy arguing and rehashing resolved points (next).

Personally, I would prefer an even stronger marker, such as a different keyword,

Please don't rehash. A different keyword breaks use-cases including function expressions (remember, we can't use a restricted production based on [no LineTerminator here] for 'generator' if it can start an arbitrary primary expression).

but * is adequate.

It's more than adequate, but I won't rehash. :-|

Programming language need to be designed for people.

This begs the question of how Python, Ruby, Lua get by without a head sigil. Don't "people" use those languages too? C'mon!

Inferring which functions are GeneratorFunction by the presences of yield

This forgets the zero-yield basis case, but nm.

may be fine for compilers but it isn't good enough for human readers or writiers.

Python, etc., have human readers and writers.

I'm taking Yuichi's side here not just be argumentative. We need better discourse and stronger consensus. Up your game! :-P

# Brendan Eich (11 years ago)

Brendan Eich wrote:

A GeneratorFunction's body is evaluated sometime after its call returns.

This is ill-stated. You mean a continuation of a yield in its body is evaluated, not the whole body (re-)evaluated.

Of course, there may be no yield, or the yield may not be reached. Yuichi pointed out similarity with return.

Sorry, now I get to be tough with myself: your "its call" threw me, my mistake. I was thinking a call to g.next() given g = gen() for a generator named gen. But diagramming the sentence, you mean the call gen(), and your statement is well-stated.

# Mark S. Miller (11 years ago)

I think you miss my point, or I miss your's. I am not talking about how many times the code runs or even whether the code runs at all. I thought I made that clear. I am talking about whether the code in the callee activation runs after the caller resumes.

Allen clearly and separately makes the same point.

Brendan, your response to Allen & I, citing Yuichi, misses this point as well.

# Mark S. Miller (11 years ago)

Yes, that is the call I mean as well.

# Brendan Eich (11 years ago)

Mark S. Miller wrote:

Brendan, your response to Allen & I, citing Yuichi, misses this point as well.

No, I get that point and ack'ed it to Allen:

"""

A regular Function's body is evaluated before its call returns.

Yes, generators have an implicit yield; at the top. Now you have hit an essential difference with other functions.

"""

I only just found time to read erights.org/data/irrelevance.html -- good stuff. Implicit among all code readers. In the Unix kernel of old, a single-threaded program except for interrupts, one had to know what function might sleep(). Deep continuations considered harmful.

# Till Schneidereit (11 years ago)

On Sun, Sep 1, 2013 at 2:43 AM, Brendan Eich <brendan at mozilla.com> wrote:

Lots of constructors/factories out there. An essential (see Aristotle) argument for why function* for generator syntax (ignoring trumping reasons 1&2) must say why this particular factory needs special (a la function*) head syntax.

For all non-generator functions, one important assumption for reading them holds: they always start with the first instruction, and any (potential) deviations from linear control flow are visible exactly where they (might) happen. Not so for generators: to understand what invoking a generator might do, you have to look at all the potential entry points, i.e., all instructions following a yield in the control flow. If you want to do more localized reasoning and are interested in a specific invocation, you also have to reason about which might be the relevant one. Granted, that is essentially state and any function's control flow can be state-dependent, so this point might be less important.

Still, having to look at an unknown number of entry points to understand how control flows through a piece of code seems like something you'll want to know about. Without searching the code for "yield".

# Yuichi Nishiwaki (11 years ago)

I thought Id agreed to #1 and #2 but seems to have failed to communicate that to you, Alright about 2 of them, thanks :)

# Yuichi Nishiwaki (11 years ago)

I don't think I miss it, but the example I took was somohow bot clear. I meant you can get to know if the code will run immediately or after the habdle back, by reading the code in the same way as you do a normal function.

# François REMY (11 years ago)

I know pretty well I’m probably not going to convince the believers here, but this whole “we need an indication at the beginning of the function” thing is kinda not making sense.

For starter, the generator function always starts at its first line. If what you {Till Schneidereit} mean is that the execution can resumes at another line when someome call .next() on the iterator, then we speak about something else, which is absolutely no different than

function SomeIterator() {

 function onFirstCalll(v) {

     

     // continue execution

     ...


     // next step in generator

     resumeDoSomething = onSecondCall;

     return someYieldedValue;

     

 }


 function onSecondCall(v) {

     

     // continue execution

     ...

     

     // next step in generator

     resumeDoSomething = onExtraCall;

     return someYieldedValue;

     

 }


 function onExtraCall() {

     throw new Error(“The iterator cannot yield more values”)

 }

 


 // generator boilerplate

 var resumeDoSomething = onFirstCalll;


 return { 

     next: function next(v) {

          return resumeDoSomething(v);

     },

     ...

 };

}

for which there’s no specific indication required. As noted before in the discussion, most programming languages providing “yield” support do not require anything specific to support it. Interestingly, VB.NET is not one of those, but they deliberately choose some non-function syntax fwiw.

In all honesty, Async functions and Promise-returning functions can very often be more challenging to grasp than iterators and there’s no “syntax flag” for those things.

The best way to tell what your function does is to choose a name that makes clear how its internal working behaves, and possibly some informational return-type information (via a comment or Typescript-like preprocessors), not by adding a distracting and non-self-descriptive star symbol next to the function keyword.

Also, I totally dislike the fact I can’t use “yield” in a lambda function because of this star thing. I can totally imagine a function taking an iterator as argument, and being able to use a lambda function could totally make sense to define the iterator. The star syntax is an arbitrary and not very useful restriction, in my opinion.

De : Till Schneidereit Envoyé : ‎samedi‎ ‎31‎ ‎août‎ ‎2013 ‎18‎:‎05 À : Brendan Eich Cc : es-discuss

On Sun, Sep 1, 2013 at 2:43 AM, Brendan Eich <brendan at mozilla.com> wrote:

Lots of constructors/factories out there. An essential (see Aristotle) argument for why function* for generator syntax (ignoring trumping reasons 1&2) must say why this particular factory needs special (a la function*) head syntax.

For all non-generator functions, one important assumption for reading them holds: they always start with the first instruction, and any (potential) deviations from linear control flow are visible exactly where they (might) happen. Not so for generators: to understand what invoking a generator might do, you have to look at all the potential entry points, i.e., all instructions following a yield in the control flow. If you want to do more localized reasoning and are interested in a specific invocation, you also have to reason about which might be the relevant one. Granted, that is essentially state and any function's control flow can be state-dependent, so this point might be less important.

Still, having to look at an unknown number of entry points to understand how control flows through a piece of code seems like something you'll want to know about. Without searching the code for "yield".

# Mark S. Miller (11 years ago)

On Sat, Aug 31, 2013 at 6:55 PM, François REMY < francois.remy.dev at outlook.com> wrote:

I know pretty well I’m probably not going to convince the believers here, but this whole “we need an indication at the beginning of the function” thing is kinda not making sense.

For starter, the generator function always starts at its first line. If what you {Till Schneidereit} mean is that the execution can resumes at another line when someome call .next() on the iterator, then we speak about something else, which is absolutely no different than

function SomeIterator() {

 function onFirstCalll(v) {

     // continue execution

Whereas On Sat, Aug 31, 2013 at 3:48 PM, Mark S. Miller <erights at google.com> wrote:

[...] The only contextual knowledge the reader needs in order to know this is that there are no intermediate function definitions within f wrapping code sequence 2 -- i.e., that code sequence 2 is code of the function f itself, as opposed to code of a function within function a. It suffices to check that there are no unbalanced function definition starts in code sequence 1. [...]

Your "function onFirstCalll(v) {" obviously violates this condition in precisely the way I meant.

In all honesty, Async functions and Promise-returning functions can very often be more challenging to grasp than iterators and there’s no “syntax flag” for those things.

For async functions:

Today: "Q.async(function*"

Hopefully in ES7: "function!"

Granted that promise-returning functions can be difficult to grasp for their own reasons. But without one of the above markers they can't create this particular confusion.

# François REMY (11 years ago)

[...] The only contextual knowledge the reader needs in order to know this is that there are no intermediate function definitions within f wrapping code sequence 2 -- i.e., that code sequence 2 is code of the function f itself, as opposed to code of a function within function a. It suffices to check that there are no unbalanced function definition starts in code sequence 1. [...]

Your "function onFirstCalll(v) {" obviously violates this condition in precisely the way I meant.

You can find a yield statement as quickly as you can find much more quickly than you can find whether any existing inner function is used for async patterns or not. This "introductory keyword" stuff is a belief which cannot be backed by any assessable fact, because it simply do not improve code readability.

In all honesty, Async functions and Promise-returning functions can very often be more challenging to grasp than iterators and there’s no “syntax flag” for those things.

For async functions:

Today: "Q.async(function*"

Hopefully in ES7: "function!"

If the goal is to make sure when we will /really/ need some innovative syntax in the future we will have run out of every easy to write token combination, as well as transforming JS into a cryptic Perl-like code, yes, that seem great to me ;-)

If the goal is to make the code clear, sorry using random glyphs in a place where they aren't expected doesn't seem like the best plot for a success story. I hope the directors of the JS movie are good and know what they're doing. I've come to learn the TC39 committee members usually have good ideas even if they seem bad initially. I hope this is the case again this time...

By the way, you didn’t reply to this:

Also, I totally dislike the fact I can’t use “yield” in a lambda function because of this star thing. I can totally imagine a function taking an iterator as argument, and being able to use a lambda function could totally make sense to define the iterator. The star syntax is an arbitrary and not very useful restriction, in my opinion.

If even async code is somehow going to use a custom syntax, we will end up in a case where lambda's will only cover a small fraction of the function needs, and you may have to refactor your lambda to functions in some cases. This seems like a bummer to me.

# Mark Miller (11 years ago)

On Sat, Aug 31, 2013 at 8:34 PM, François REMY < francois.remy.dev at outlook.com> wrote:

[...] The only contextual knowledge the reader needs in order to know this is that there are no intermediate function definitions within f wrapping code sequence 2 -- i.e., that code sequence 2 is code of the function f itself, as opposed to code of a function within function a. It suffices to check that there are no unbalanced function definition starts in code sequence 1. [...]

Your "function onFirstCalll(v) {" obviously violates this condition in precisely the way I meant.

You can find a yield statement as quickly as you can find much more quickly than you can find whether any existing inner function is used for async patterns or not. This "introductory keyword" stuff is a belief which cannot be backed by any assessable fact, because it simply do not improve code readability.

In all honesty, Async functions and Promise-returning functions can very often be more challenging to grasp than iterators and there’s no “syntax flag” for those things.

For async functions:

Today: "Q.async(function*"

Hopefully in ES7: "function!"

If the goal is to make sure when we will /really/ need some innovative syntax in the future we will have run out of every easy to write token combination, as well as transforming JS into a cryptic Perl-like code, yes, that seem great to me ;-)

If the goal is to make the code clear, sorry using random glyphs in a place where they aren't expected doesn't seem like the best plot for a success story. I hope the directors of the JS movie are good and know what they're doing. I've come to learn the TC39 committee members usually have good ideas even if they seem bad initially. I hope this is the case again this time...

That is nice to hear, and quite a track record to live up to. On behalf of all TC39 if I may, thanks.

However, I cannot honestly leave you to expect this to happen again in this case. I think we've stated the case for "function*" as clearly as we're going to. It is a tradeoff. Depending on one's weightings of the issues, one can honestly disagree. I expect that's all that's going on here.

In any case, because of Brendan's reasons #1 and #2, our disagreement on #3 doesn't actually matter. We need some distinguishing syntactic marker regardless. No one has suggested anything less painful than "function*"

By the way, you didn’t reply to this:

Also, I totally dislike the fact I can’t use “yield” in a lambda function because of this star thing. I can totally imagine a function taking an iterator as argument, and being able to use a lambda function could totally make sense to define the iterator. The star syntax is an arbitrary and not very useful restriction, in my opinion.

If even async code is somehow going to use a custom syntax, we will end up in a case where lambda's will only cover a small fraction of the function needs, and you may have to refactor your lambda to functions in some cases. This seems like a bummer to me.

I have previously lamented this problem on es-discuss and asked for suggestions. I agree that this problem is genuinely painful and continue to welcome suggestions.

# Brendan Eich (11 years ago)

Till Schneidereit <mailto:till at tillschneidereit.net> August 31, 2013 6:05 PM On Sun, Sep 1, 2013 at 2:43 AM, Brendan Eich <brendan at mozilla.com <mailto:brendan at mozilla.com>> wrote:

Lots of constructors/factories out there. An essential (see
Aristotle) argument for why function* for generator syntax
(ignoring trumping reasons 1&2) must say why *this* particular
factory needs special (a la function*) head syntax.

For all non-generator functions, one important assumption for reading them holds: they always start with the first instruction, and any (potential) deviations from linear control flow are visible exactly where they (might) happen. Not so for generators:

True so far, and I said so later in the same message:

"""

A regular Function's body is evaluated before its call returns.

Yes, generators have an implicit yield; at the top. Now you have hit an essential difference with other functions.

"""

but then (in a glass house myself, not throwing stones), you move away from pointing out the leading implicit yield, to talking about later explicit yields. Those are different for generators too, assuming there are any -- but since a generator can be explicit yield free, yet still has that implicit yield at the front.

So I think the later yields are not sufficient, even though present in by far the common cases, to argue for an essential difference. It's the leading implicit yield that makes generator functions different enough from regular functions to merit function* syntax.

# François REMY (11 years ago)

I've come to learn the TC39 committee members usually have good ideas even if they seem bad initially. I hope this is the case again this time...

That is nice to hear, and quite a track record to live up to. On behalf of all TC39 if I may, thanks.

Well, I don't think I deserve such thanks just for stating my thrust in this group, but I can get how it must feel good to hear in the sea of complaints that you're probably used to receive ;-) It's the same story for any group, for what it's worth. People easily notice what's wrong, and consider all the goodness as granted. That's how humans are made, and how we progresses and avoids regression.

However, I cannot honestly leave you to expect this to happen again in this case. I think we've stated the case for "function*" as clearly as we're going to.

It is a tradeoff.

My gut tells me we're running out of such tradeoffs in JS at speed of light recently. There must be another way. And if such way exists, we shall find it.

# Jussi Kalliokoski (11 years ago)

Sorry if this has been brought up before, but why function * (which looks like a pointer to a function more than a generator) instead of something clearer, e.g. generator myGenerator () {}? I see the obvious ASI hazard, but this can be mitigated by not allowing unnamed generators, e.g. { myGenerator: generator _ () {} }, which would not at least be worse than the current syntax (star required, dummy identifier required, does it make a difference?), but would be more descriptive. If you see something like this for the first time, instead of going "wtf, pointer?!", you understand that it is a generator, and if have no prior experience of generators in other languages can google the concept.

If a more descriptive keyword sounds like a no-no (rationale appreciated), please let's at least consider using a different operator than the star.

# Brendan Eich (11 years ago)

Jussi Kalliokoski <mailto:jussi.kalliokoski at gmail.com> September 1, 2013 5:38 AM Sorry if this has been brought up before,

It has, even in this thread.

but why function * (which looks like a pointer to a function more than a generator

This is JS, please take off your C/C++ hat :-P.

) instead of something clearer, e.g. generator myGenerator () {}? I see the obvious ASI hazard, but this can be mitigated by not allowing unnamed generators, e.g. { myGenerator: generator _ () {} },

This doesn't work in general, it is backward-incompatible. If someone bound or assigned to generator in-scope, your proposed change could break compatibility -- or else require parsing to depend on name binding.

foo = generator bar() {}

Remember, if there wasn't an error, ASI doesn't apply. Trying to "patch" this bad theory with a [no LineTerminator here] restriction to the right of 'generator' does not work in the grammar without reserving 'generator' -- we can't put that restriction to the right of every Identifier on the right of every expression production.

Please stamp this on all inner eyelids so I don't have to repeat it ad nauseum.

# Jussi Kalliokoski (11 years ago)

On Sun, Sep 1, 2013 at 7:56 PM, Brendan Eich <brendan at mozilla.com> wrote:

Jussi Kalliokoski <mailto:jussi.kalliokoski@**gmail.com<jussi.kalliokoski at gmail.com>

September 1, 2013 5:38 AM

Sorry if this has been brought up before,

It has, even in this thread.

My apologies! Ran a quick scan with my eyes and a find for generator ( and generator( to no results so decided to bring this up after contemplating it for quite a while now since the topic is relevant.

but why function * (which looks like a pointer to a function more than

a generator

This is JS, please take off your C/C++ hat :-P.

Sure, but let's not ignore that this syntax already has a special meaning in the language family JS syntax is heavily based on. Like I asked, why does it have to be the star? Why not tilde? Or plus? Why take something that already has a completely different meaning in other languages?

) instead of something clearer, e.g. generator myGenerator () {}? I see

the obvious ASI hazard, but this can be mitigated by not allowing unnamed generators, e.g. { myGenerator: generator _ () {} },

This doesn't work in general, it is backward-incompatible. If someone bound

or assigned to generator in-scope, your proposed change could break compatibility -- or else require parsing to depend on name binding.

foo = generator bar() {}

Remember, if there wasn't an error, ASI doesn't apply. Trying to "patch" this bad theory with a [no LineTerminator here] restriction to the right of 'generator' does not work in the grammar without reserving 'generator' -- we can't put that restriction to the right of every Identifier on the right of every expression production.

Can you elaborate on this, please, I'm confused? Why can't we restrict the syntax? Unrestricted syntax is why we are having this discussion in the first place. What's the negative effect of reserving 'generator'? In my opinion the parser saying "ohmigod" and going back a few cycles when hitting generator is a lot better than humans having to read what we are going for now. After all, what's the point of programming languages aside readability? How come is it not OK to disallow the syntax in your example to be a valid generator, regardless of whether generator is defined or not? What am I missing?

I'm sorry if I'm asking stupid questions, but the only stupid question is the one left unasked.

# Brendan Eich (11 years ago)
    but why `function *` (which looks like a pointer to a function
    more than a generator


This is JS, please take off your C/C++ hat :-P.

Sure, but let's not ignore that this syntax already has a special meaning in the language family JS syntax is heavily based on.

What syntax? 'function' is not a reserved word in C or C++. It is in AWK, which is arguably in the C family. Sorry, but JS syntax is not bound to evolve only in ways that are disjoint from keyword-free reinterpretation as C or C++.

Like I asked, why does it have to be the star?

Yes, it has to be star. This is not the hill you want to die on, metaphorically speaking. TC39 reached consensus based on a championed proposal. Re-opening this minor design decision needs strong justification. Trying to avoid looking like C or C++ at a glance is not strong justification.

Why not tilde? Or plus? Why take something that already has a completely different meaning in other languages?

Rust uses tilde for unique references / linear types. Someone has to pay.

) instead of something clearer, e.g. `generator myGenerator ()
{}`? I see the obvious ASI hazard, but this can be mitigated by
not allowing unnamed generators, e.g. `{ myGenerator: generator _
() {} } `,


This doesn't work in general, it is backward-incompatible. If
someone bound or assigned to generator in-scope, your proposed
change could break compatibility -- or else require parsing to
depend on name binding.

foo = generator
bar()
{}

Remember, if there wasn't an error, ASI doesn't apply. Trying to
"patch" this bad theory with a [no LineTerminator here]
restriction to the right of 'generator' does not work in the
grammar without reserving 'generator' -- we can't put that
restriction to the right of every Identifier on the right of every
expression production.

Can you elaborate on this, please, I'm confused? Why can't we restrict the syntax?

You have to propose exactly how you want to "restrict the syntax".

As I just wrote, we cannot restrict all productions with Identifier in their right-hand sides to forbid line terminators after. Any restriction would be word-sensitive and require 'generator' to be reserved. Then the problem becomes backward incompatibility of the kind I showed. To avoid breaking such code (and other cases not yet thought of) requires a grammatical restriction of some sort. What sort?

Unrestricted syntax is why we are having this discussion in the first place. What's the negative effect of reserving 'generator'? In my opinion the parser saying "ohmigod"

Please stop informal rambling and specify exactly what you mean.

# Jussi Kalliokoski (11 years ago)

On Mon, Sep 2, 2013 at 12:09 AM, Brendan Eich <brendan at mozilla.com> wrote:

    but why `function *` (which looks like a pointer to a function
    more than a generator


This is JS, please take off your C/C++ hat :-P.

Sure, but let's not ignore that this syntax already has a special meaning in the language family JS syntax is heavily based on.

What syntax? 'function' is not a reserved word in C or C++. It is in AWK, which is arguably in the C family. Sorry, but JS syntax is not bound to evolve only in ways that are disjoint from keyword-free reinterpretation as C or C++.

No, 'function' is not a reserved word in C/++, who said it was? I'm saying function *myGenerator looks a lot like <type> *<identifier>.

Like I asked, why does it have to be the star?

Yes, it has to be star. This is not the hill you want to die on, metaphorically speaking. TC39 reached consensus based on a championed proposal. Re-opening this minor design decision needs strong justification. Trying to avoid looking like C or C++ at a glance is not strong justification.

I'm aware of the decision, the rationale behind it is what I'm looking for. Or was star picked just because? I suppose it looking confusing to me doesn't qualify as a strong justification to revert a decision like this.

I'm obviously not going to convince you that the star is a bad idea?

Why not tilde? Or plus? Why take something that already has a completely

different meaning in other languages?

Rust uses tilde for unique references / linear types. Someone has to pay.

Exclamation mark? Percentage symbol? There's a dozen other punctuation options, maybe one of them would make it look less like something completely different in one of the most popular programming language families.

) instead of something clearer, e.g. `generator myGenerator ()
{}`? I see the obvious ASI hazard, but this can be mitigated by
not allowing unnamed generators, e.g. `{ myGenerator: generator _
() {} } `,


This doesn't work in general, it is backward-incompatible. If
someone bound or assigned to generator in-scope, your proposed
change could break compatibility -- or else require parsing to
depend on name binding.

foo = generator
bar()
{}

Remember, if there wasn't an error, ASI doesn't apply. Trying to
"patch" this bad theory with a [no LineTerminator here]
restriction to the right of 'generator' does not work in the
grammar without reserving 'generator' -- we can't put that
restriction to the right of every Identifier on the right of every
expression production.

Can you elaborate on this, please, I'm confused? Why can't we restrict the syntax?

You have to propose exactly how you want to "restrict the syntax".

As I just wrote, we cannot restrict all productions with Identifier in their right-hand sides to forbid line terminators after. Any restriction would be word-sensitive and require 'generator' to be reserved. Then the problem becomes backward incompatibility of the kind I showed. To avoid breaking such code (and other cases not yet thought of) requires a grammatical restriction of some sort. What sort?

So generator [no LineTerminator here] BindingIdentifier [no LineTerminator here] ( FormalParameters ) { FunctionBody } couldn't be done? The parser can't be word-sensitive without flagging that word as a keyword? Sounds like an arbitrary limitation that should be fixed.

Even generator function BindingIdentifieropt ( FormalParameters ) { FunctionBody } would be better at describing what it does than what we have.

# Brendan Eich (11 years ago)

Jussi Kalliokoski <mailto:jussi.kalliokoski at gmail.com> September 1, 2013 10:03 PM On Mon, Sep 2, 2013 at 12:09 AM, Brendan Eich <brendan at mozilla.com <mailto:brendan at mozilla.com>> wrote:

            but why `function *` (which looks like a pointer to a
    function
            more than a generator


        This is JS, please take off your C/C++ hat :-P.


    Sure, but let's not ignore that this syntax already has a
    special meaning in the language family JS syntax is heavily
    based on.


What syntax? 'function' is not a reserved word in C or C++. It is
in AWK, which is arguably in the C family. Sorry, but JS syntax is
not bound to evolve only in ways that are disjoint from
keyword-free reinterpretation as C or C++.

No, 'function' is not a reserved word in C/++, who said it was? I'm saying function *myGenerator looks a lot like <type> *<identifier>.

We're going in circles: I'm saying (I said) take off the C/C++ hat.

JS's future syntax is not under a do-not-mimic-C/C++-ignoring-keywords-and-semantics constraint.

    Like I asked, why does it have to be the star?


Yes, it has to be star. This is not the hill you want to die on,
metaphorically speaking. TC39 reached consensus based on a
championed proposal. Re-opening this minor design decision needs
strong justification. Trying to avoid looking like C or C++ at a
glance is not strong justification.

I'm aware of the decision, the rationale behind it is what I'm looking for. Or was star picked just because?

No, think about yield* for delegation. We want consonance, reuse of "generator sigil".

Your comments on the grammar show continued informality and lack of familiarity with parsing theory in general, and the ECMA-262 grammar formalisms in particular. We don't want to split 'generator' out from Identifier, and special-case its syntax in PrimaryExpressions (which must be covered by a cover-grammar that also covers destructuring). We don't have a convenient formalism for such special-casing.

What's more, special-casing 'generator' is more than a spec and implementation front-end complexity tax. It makes a longer and more complex path dependency for any future syntax extension nearby (e.g., Mark's function! for async function syntax, proposed for ES7

# Jussi Kalliokoski (11 years ago)

On Mon, Sep 2, 2013 at 8:47 AM, Brendan Eich <brendan at mozilla.com> wrote:

Jussi Kalliokoski <mailto:jussi.kalliokoski@**gmail.com<jussi.kalliokoski at gmail.com>

September 1, 2013 10:03 PM

No, 'function' is not a reserved word in C/++, who said it was? I'm saying

function *myGenerator looks a lot like <type> *<identifier>.

We're going in circles: I'm saying (I said) take off the C/C++ hat.

JS's future syntax is not under a do-not-mimic-C/C++-ignoring-**keywords-and-semantics constraint.

Of course not. That doesn't mean we should ignore what other common languages do with the same syntax. And at best, with my C/++ skills, it's more like a kippah than a real hat. ^^

     Like I asked, why does it have to be the star?
Yes, it has to be star. This is not the hill you want to die on,
metaphorically speaking. TC39 reached consensus based on a
championed proposal. Re-opening this minor design decision needs
strong justification. Trying to avoid looking like C or C++ at a
glance is not strong justification.

I'm aware of the decision, the rationale behind it is what I'm looking for. Or was star picked just because?

No, think about yield* for delegation. We want consonance, reuse of "generator sigil".

Googling generator sigil yields online magic symbol generators... Not what I was looking for, I think. :) Is the star after yield any less arbitrary?

Your comments on the grammar show continued informality and lack of familiarity with parsing theory in general, and the ECMA-262 grammar formalisms in particular.

They probably do since I am not familiar with parsing theory in general, but I probably represent a large portion of the community with that disability (which I hope to repair at some point). I wouldn't ask the questions if I knew the answers, now would I. To me this seems just like arbitrary limitations where it's somehow impossible to add an if statement in the parser.

We don't want to split 'generator' out from Identifier, and special-case

its syntax in PrimaryExpressions (which must be covered by a cover-grammar that also covers destructuring). We don't have a convenient formalism for such special-casing.

All right, so it would be a much larger effort to specify it?

What's more, special-casing 'generator' is more than a spec and implementation front-end complexity tax. It makes a longer and more complex path dependency for any future syntax extension nearby (e.g., Mark's function! for async function syntax, proposed for ES7 -- controversial, and perhaps ^ is better than !, but in any case this is easy to do given function*, not so easy to do given generator|function syntax). Special cases are a smell.

I agree with special cases being a smell, but hacks are a smell too (hacks lead to the need for special cases), and function * is definitely a hack around the limitations we have (arbitrary or not). So two smelly things, the difference is that only one of them conveys the intended meaning at first glance, but only one has been agreed upon

Finally, no way will we lumber everyone writing generators with a double-keyword 'generator function'. That's too much on several dimensions. TC39's consensus for function* is worth keeping, over against your inability to take off the C/C++ hat. Of this I am certain, even if the * is somewhat arbitrary (but see above about yield*).

I also realized a bit after sending the message that it wouldn't even avoid the [no LineTerminator here] problem, sorry. >,<

So at this point, to be frank and with the best intentions, I think you're being a sore loser ;-). It's no fun to lose, I've had to learn to cope over the years big-time (JS in its rushed glory; ES4; etc.). This '*' is very small potatoes, as the saying goes.

Don't worry, I know quite well how to lose, in fact I consider losing as one of the things I'm best at. But when I'm proven wrong, I want to understand why I was wrong. Where you are now seeing a sore loss, I see a triumph in learning new things. ;)

However I see this is a sunk cost and beating a dead horse, so I rest my case (that's not to say I wouldn't appreciate my questions getting answered). Sorry for making you repeat yourself.

# Brendan Eich (11 years ago)

Jussi Kalliokoski wrote:

Is the star after yield any less arbitrary?

Not much -- it conjures Kleene's star, worth something (not much? enough!).

Your comments on the grammar show continued informality and lack
of familiarity with parsing theory in general, and the ECMA-262
grammar formalisms in particular.

They probably do since I am not familiar with parsing theory in general, but I probably represent a large portion of the community with that disability (which I hope to repair at some point). I wouldn't ask the questions if I knew the answers, now would I. To me this seems just like arbitrary limitations where it's somehow impossible to add an if statement in the parser.

We don't want to mess around with ambiguity. The smell of a suffix character for function is strictly less than the smell of a sub-grammar for 'generator' distinct from other identifiers, with newline sensitivity.

We don't want to split 'generator' out from Identifier, and
special-case its syntax in PrimaryExpressions (which must be
covered by a cover-grammar that also covers destructuring). We
don't have a convenient formalism for such special-casing.

All right, so it would be a much larger effort to specify it?

The work involves splitting Identifier :: IdentifierName but not ReservedWord into 'generator' | IdentifierNotGenerator and adding IdentifierNotGenerator :: IdentifierName but not ('generator' or ReservedWord), then splitting Identifier uses and coping with the cover grammar complexity. I haven't done the work to make sure it's sound. Much bigger fish to fry, rotten smell already.

# Jussi Kalliokoski (11 years ago)

On Mon, Sep 2, 2013 at 10:49 AM, Brendan Eich <brendan at mozilla.com> wrote:

Jussi Kalliokoski wrote:

Is the star after yield any less arbitrary?

Not much -- it conjures Kleene's star, worth something (not much? enough!).

Fair enough, I suppose Kleene's star with its "zero or more" semantics comes close enough, but in that case, shouldn't the star be a suffix to the value rather than a prefix (like we already have with RegExp)? ;)

 Your comments on the grammar show continued informality and lack
of familiarity with parsing theory in general, and the ECMA-262
grammar formalisms in particular.

They probably do since I am not familiar with parsing theory in general, but I probably represent a large portion of the community with that disability (which I hope to repair at some point). I wouldn't ask the questions if I knew the answers, now would I. To me this seems just like arbitrary limitations where it's somehow impossible to add an if statement in the parser.

We don't want to mess around with ambiguity. The smell of a suffix character for function is strictly less than the smell of a sub-grammar for 'generator' distinct from other identifiers, with newline sensitivity.

All right, although in my head it's better for the parser to have to bear the bad smell than people writing and reading the code. But it seems the general course with ES currently is to keep the smell at the end programmers' end rather than the parser's end and let compile-to-JS fix the resulting smell in the end programmers' end. :)

We don't want to split 'generator' out from Identifier, and
special-case its syntax in PrimaryExpressions (which must be
covered by a cover-grammar that also covers destructuring). We
don't have a convenient formalism for such special-casing.

All right, so it would be a much larger effort to specify it?

The work involves splitting Identifier :: IdentifierName but not ReservedWord into 'generator' | IdentifierNotGenerator and adding IdentifierNotGenerator :: IdentifierName but not ('generator' or ReservedWord), then splitting Identifier uses and coping with the cover grammar complexity. I haven't done the work to make sure it's sound. Much bigger fish to fry, rotten smell already.

Fair enough. If the result value < effort value, there's not much to do.

# François REMY (11 years ago)

I'm back. Not sure I totally figured it out, but I thought it was probably time to "yield" my reasoning before iterating further ;-)

To achieve a different result, I figured out we probably needed to start from a different sets of initial assumptions. So here are my new set of assumptions:

  • We don't need to support the yield operator in non-strict code. If someone is in the process of defining a new function, it can simply trigger the strict mode in this new iterator function if he wants to yield inside it. However, that shouldn't be needed in the future as ES strict is the new default in modules, and we can expect that almost all iterators will be defined inside the strict regions thereby defined. This also guarantees that "yield" is not used in a context where strange things may happen, and comes together with a whole set of new features.

  • We don't want to introduce magic stuff where it isn't needed, but we want to keep most of the power of syntaxic sugar. Iterators are kinda achievable in pure ES5, only complex to write (state machine) and sometimes even more to read. However we should probably allow someone that want to implement is own "yield" logic to do so if he wants to, and not restrict the Iterator usage to the sole built-in "yield syntax" (this follows the Extensible Web principles).

  • We want to keep the idea that the reader should quickly understand when reading a function that it create an iterator. However, since creating state machines can be useful for multiple purposes, we could probably allow creating a state machine function without all the magic related to iterators.

  • Since introducing keywords is hard, we should focus on providing a good pattern library (at runtime) instead of syntax-related tricks (at compile-time)

When working under this set of assumptions, I came with the following idea:

function getNumberIteration(filter) {
	return new Iterator(=> {
		
		var i = 0; while(1) {
			if(filter(i)) yield i;
			i++;
		}
		
	});
}
function getNumberIteration(filter) {
	return new Iterator(=> {
		
		var i = 0; return @NEXT(); 
		
		function @NEXT(injectedValue) {
			while(1) {
				if(filter(i)) { 
					
					return { 
						value: i, 
						next: @NEXT
					};
					
				}
				i++;
			}
		}
		
	});
}

Basically, using yield into a function create a state machine for the function and does run the function normally until the first encountered state switch (first yield statement here). In some sense, the function is almost normal, we could barely consider this kind of "yield" like a new kind of "return" that also return a pointer to a function that allows to continue the execution. You can totally write that in plain JS which will allow TypeScript-like compilers to generate for you the ES5-compatible code for your ES6 iterator, and use it on ES5-compatible browsers the exact same way you do on an ES6-browser.

It also allow you to use lambda functions, which is quite a great nice-to-have.

So, let's see how I address the 3 reasons behind function* :

Three reasons for function* syntax:

  1. Opt-in required for backward-incompatible definition of 'yield' as low-precedence unary prefix operator.

Works as-is in modules, requires defining "use strict" in the function body if you want to use outside the strict context.

  1. Zero-yield (no yield in body) basis case, useful for delegation via yield* from another generator.

Removed. The zero-yield logic is encapsulated into the Iterator class, which only call the iterator function when required.

  1. Decorator to alert the reader that the body contains yield (ignoring 2 for a moment) reason.

Provided by the fact you have to create an instance of Iterator, which instantiation should be pretty easy to spot.

This is certainly another set of tradeoffs, but I tend to like it more (even if it may still require tweaks or may just don't fit for some reason I didn't think about) than the current one.

What's your opinon?

# Jason Orendorff (11 years ago)

On Tue, Sep 3, 2013 at 9:54 PM, François REMY <francois.remy.dev at outlook.com> wrote:

  • We don't want to introduce magic stuff where it isn't needed, but we want to keep most of the power of syntaxic sugar. Iterators are kinda achievable in pure ES5, only complex to write (state machine) and sometimes even more to read. However we should probably allow someone that want to implement is own "yield" logic to do so if he wants to, and not restrict the Iterator usage to the sole built-in "yield syntax" (this follows the Extensible Web principles).

It sounds like you are saying that generators are too high-level, and it would be better to expose a lower-level primitive.

But what would that lower-level primitive be? What operations would it expose?

When working under this set of assumptions, I came with the following idea: [...] Basically, using yield into a function create a state machine for the function and does run the function normally until the first encountered state switch (first yield statement here). In some sense, the function is almost normal, we could barely consider this kind of "yield" like a new kind of "return" that also return a pointer to a function that allows to continue the execution. You can totally write that in plain JS which will allow TypeScript-like compilers to generate for you the ES5-compatible code for your ES6 iterator, and use it on ES5-compatible browsers the exact same way you do on an ES6-browser.

How is any of this different from generators?

goo.gl/Flf2ru

# François REMY (11 years ago)

It sounds like you are saying that generators are too high-level, and it would be better to expose a lower-level primitive.

But what would that lower-level primitive be? What operations would it expose?

State machines. As you can see for your Traceur example, there are two things here: the state machine function, and the Iterator wrapper. I propose ES6 ships a wrapper (Iterator) and a syntaxic sugar (yield) to make creating state machines easier.

For example, having the yield logic independant of the Iterator wrapper could allow creative usages like:

function DeterministicSolutionFinder(func, valuesToTry) {         let queue = [func]; while(queue.length !== 0) {             let current = queue.shift();             for(let value of valuesToTry) {                                 let currentResult = current(value);                 if (!currentResult) {                     continue                                     } else if(!(currentResult instanceof YieldReturn)) {                     return currentResult                                     } else if(!(currentResult.done)) {                     queue.push(currentResult.next)                                     }                             }         }     }         DeterministicSolutionFinder(=>{               var x = [ yield, yield, yield, yield ];        if( (x[0]||x[1]) && (!x[1]||!x[2]) && ...) { return x; }            },[true,false])

I hereby used the underlying behavior of "yield" to create a basic fork() in the special case of functionnal-programming-compatible functions (ie: variables are defined only once and previously defined variables are not modified during the function execution to prevent side-effects on further executions).

You simply cannot do the same thing if you've to restrict yourself to the Iterator wrapper.

How is any of this different from generators?

goo.gl/Flf2ru

The difference is that you could use the "ES5 version" with the native Iterator wrapper, you're not forced to build your own if the browser already ship an Iterator wrapper (it could just be a polyfill for older browsers).

The other difference is that there's no "implied yield" at the beginning of the function. Yield is a special kind of return, but the fact a function contains a yield doesn't suddenly change its behavior completely.

You're also free to choose whichever wrapper implementation fits your needs, which is kinda great.