François REMY (2013-09-04T02:54:30.000Z)
Hi, 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.


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


> 3. 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?
Francois
domenic at domenicdenicola.com (2013-09-08T01:01:05.628Z)
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:

```js
function getNumberIteration(filter) {
	return new Iterator(=> {
		
		var i = 0; while(1) {
			if(filter(i)) yield i;
			i++;
		}
		
	});
}
```

```js
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.


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


> 3) 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?