On Sep 9, 2012, at 3:32 PM, Brendan Eich wrote:
> I wanted to leave a clean example (no var and let mixing, either):
>
> function dataSnapshot(aCollection) {
> let snapshot = aCollection.clone();
> let i = 0;
> return {
> next: function () {
> if (i == snapshot.length)
> throw StopIteration;
> return snapshot[i++];
> }
> };
> }
>
> (I usually prefer post-increment for loop-ish constructs. Old C hacker here.)
>
> Again, anyone trying to avoid the .clone() call would be disappointed. Anyone
> trying to avoid the extra level of function nesting would be disappointed.
> There is irreducible complexity here.
>
> But the generator form is still winning:
>
> function dataSnapshot(aCollection) {
> let snapshot = aCollection.clone();
> return function*() {
> for (let i = 0; i < snapshot.length; i++){
> yield snapshot[i];
> }
> }();
> }
>
What's going on here seems clearer to me, if I think about a generator as a
unusual kind of constructor rather than an unusual kind of function that can be
suspended and resumed. From that perspective a call to the generator is
really a "constructor called as a function" that implicitly does a new, much
like several other built-in constructors. Thinking about it that way, you
might alternatively write your dataSnapshot function as:
function dataSnapshot(aCollection) {
let snapshot = aCollection.clone();
return new function*() {
for (let i = 0; i < snapshot.length; i++){
yield snapshot[i];
}
};
}
Is new'ing generators intended to be legal?
Instances of generators are iterator objects that implement a state machine
based upon the code provided as the body of the constructor. I shouldn't be
thinking about the call to the generator as returning a suspended function
activation, instead I should be think of it as simply return an object that
implements the iterator interface.
My concern about concise generator method syntax is that it makes the
generator-ness of the method appear to be an important part of the class
instance interface when it should really be an implementation detail. Consider
as class such as:
class DataCollection extends Collection {
*@iterator() {
... //implementation details
}
}
The interface of this class should be described as having an @iterator method
that returns an object that implements the abstract iterator interface.
Whether that object is an instance of a generator or a non-generator based
iterator object shouldn't be relevant to clients of this class. It's an
implementation detail that can be subject to change within impacting clients.
However, the appearance of * as the first character of the method definition
gives it an unjustified importance. I might actually prefer the above written
as:
class DataCollection extends Collection {
@iterator() {
return new function*() {
... //implementation details
}
}
}
Allen
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss