Incompatibility between generators and arrays in the Iterator protocol
If you use yield instead of return in your generator function you'll get the desired results. When using a generator function to implement iteration, you'll generally want to avoid returning a final value, since for-of ignores the return value.
The return value does have an important role to play in coroutine-style use cases.
If you use yield instead of return in your generator function you'll get the desired results. When using a generator function to implement iteration, you'll generally want to avoid returning a final value, since for-of ignores the return value. The return value does have an important role to play in coroutine-style use cases. On 2:20PM, Tue, Jun 30, 2015 Tim Jansen <ml at tjansen.de> wrote: > Hi, > > I am working on a collections library that supports the Iterable/Iterator > protocol, but I ran into a stumbling block: the iterator protocol seems to > work differently for arrays and generator functions. Array iterators set > 'done' to true *after* the last element, but function generators set 'done' > to true *on* the last element. > > Is this incompatibility intentional, or or just an implementation issue in > the browsers (tested on FF38 and Chrome 43)? I wasn't able to find any > information on this. The ES6 draft from April '15 doesn't define when > exactly 'done' is set. > > > Code example: > > var a = ['a', 'b']; > > var itA = a[Symbol.iterator]; > > itA.next(); // {value: 'a', done: false} > > itA.next(); // {value: 'b', done: false} !! > > itA.next(); // {value: undefined, done: true} > > > function* b() { > > yield 'a'; > > return 'b'; > > } > > var itB = a[Symbol.iterator]; > > itB.next(); // {value: 'a', done: false} > > itB.next(); // {value: 'b', done: true} !!! > > itB.next(); // {value: undefined, done: true} > > The difference is in the second invocation of next(), which returns true > for generator functions. That protocol makes it impossible for me to > support both generator functions and array iterators with the same > implementation - at least if I want to support 'undefined' as a valid value > in collections. I wouldn't be able to differentiate between an empty list > ([]) and a list containing undefined ([undefined]). > > > Thanks, > > Tim > > > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150630/6f788c74/attachment-0001.html>
The value set when done: true
is set is not considered part of the
iterated list, which is why you are seeing what you are seeing. The
expected behavior is defined as done: false
for all yielded values, and
done: true
when iteration has completed.
That same behavior also applies for for...of
loops for instance. For
example, see 13.7.5.13 #5c, as soon as 'done' becomes 'true' the loop exits, the returned value is
ignored. Also the same can also be seen in Array.from in 22.1.2.1 #6.g.iv
The value set when `done: true` is set is not considered part of the iterated list, which is why you are seeing what you are seeing. The expected behavior is defined as `done: false` for all yielded values, and `done: true` when iteration has completed. That same behavior also applies for `for...of` loops for instance. For example, see 13.7.5.13 <http://www.ecma-international.org/ecma-262/6.0/#sec-runtime-semantics-forin-div-ofbodyevaluation-lhs-stmt-iterator-lhskind-labelset> #5c, as soon as 'done' becomes 'true' the loop exits, the returned value is ignored. Also the same can also be seen in Array.from in 22.1.2.1 <http://www.ecma-international.org/ecma-262/6.0/#sec-array.from> #6.g.iv On Tue, Jun 30, 2015 at 11:13 AM, Tim Jansen <ml at tjansen.de> wrote: > Hi, > > I am working on a collections library that supports the Iterable/Iterator > protocol, but I ran into a stumbling block: the iterator protocol seems to > work differently for arrays and generator functions. Array iterators set > 'done' to true *after* the last element, but function generators set 'done' > to true *on* the last element. > > Is this incompatibility intentional, or or just an implementation issue in > the browsers (tested on FF38 and Chrome 43)? I wasn't able to find any > information on this. The ES6 draft from April '15 doesn't define when > exactly 'done' is set. > > > Code example: > > var a = ['a', 'b']; > > var itA = a[Symbol.iterator]; > > itA.next(); // {value: 'a', done: false} > > itA.next(); // {value: 'b', done: false} !! > > itA.next(); // {value: undefined, done: true} > > > function* b() { > > yield 'a'; > > return 'b'; > > } > > var itB = a[Symbol.iterator]; > > itB.next(); // {value: 'a', done: false} > > itB.next(); // {value: 'b', done: true} !!! > > itB.next(); // {value: undefined, done: true} > > The difference is in the second invocation of next(), which returns true > for generator functions. That protocol makes it impossible for me to > support both generator functions and array iterators with the same > implementation - at least if I want to support 'undefined' as a valid value > in collections. I wouldn't be able to differentiate between an empty list > ([]) and a list containing undefined ([undefined]). > > > Thanks, > > Tim > > > > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150630/e6cf80af/attachment.html>
Kevin is right; I think the equivalence you're looking for is:
var arrayIter = [1, 2, ..., n][Symbol.iterator]();
var genIter = (function*() { yield 1; yield 2; ... yield n; })();
Kevin is right; I think the equivalence you're looking for is: var arrayIter = [1, 2, ..., n][Symbol.iterator](); var genIter = (function*() { yield 1; yield 2; ... yield n; })(); On Tue, Jun 30, 2015 at 2:31 PM Kevin Smith <zenparsing at gmail.com> wrote: > If you use yield instead of return in your generator function you'll get > the desired results. When using a generator function to implement > iteration, you'll generally want to avoid returning a final value, since > for-of ignores the return value. > > The return value does have an important role to play in coroutine-style > use cases. > > On 2:20PM, Tue, Jun 30, 2015 Tim Jansen <ml at tjansen.de> wrote: > >> Hi, >> >> I am working on a collections library that supports the Iterable/Iterator >> protocol, but I ran into a stumbling block: the iterator protocol seems to >> work differently for arrays and generator functions. Array iterators set >> 'done' to true *after* the last element, but function generators set 'done' >> to true *on* the last element. >> >> Is this incompatibility intentional, or or just an implementation issue >> in the browsers (tested on FF38 and Chrome 43)? I wasn't able to find any >> information on this. The ES6 draft from April '15 doesn't define when >> exactly 'done' is set. >> >> >> Code example: >> >> var a = ['a', 'b']; >> >> var itA = a[Symbol.iterator]; >> >> itA.next(); // {value: 'a', done: false} >> >> itA.next(); // {value: 'b', done: false} !! >> >> itA.next(); // {value: undefined, done: true} >> >> >> function* b() { >> >> yield 'a'; >> >> return 'b'; >> >> } >> >> var itB = a[Symbol.iterator]; >> >> itB.next(); // {value: 'a', done: false} >> >> itB.next(); // {value: 'b', done: true} !!! >> >> itB.next(); // {value: undefined, done: true} >> >> The difference is in the second invocation of next(), which returns true >> for generator functions. That protocol makes it impossible for me to >> support both generator functions and array iterators with the same >> implementation - at least if I want to support 'undefined' as a valid value >> in collections. I wouldn't be able to differentiate between an empty list >> ([]) and a list containing undefined ([undefined]). >> >> >> Thanks, >> >> Tim >> >> >> >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150630/ecfed5f7/attachment.html>
On Jun 30, 2015, at 11:13 AM, Tim Jansen wrote:
Is this incompatibility intentional, or or just an implementation issue in the browsers (tested on FF38 and Chrome 43)? I wasn't able to find any information on this. The ES6 draft from April '15 doesn't define when exactly 'done' is set.
sure it does:
For example,
On Jun 30, 2015, at 11:13 AM, Tim Jansen wrote: > Is this incompatibility intentional, or or just an implementation issue in the browsers (tested on FF38 and Chrome 43)? I wasn't able to find any information on this. The ES6 draft from April '15 doesn't define when exactly 'done' is set. > > sure it does: For example, http://ecma-international.org/ecma-262/6.0/#sec-%arrayiteratorprototype%.next step 10.b http://ecma-international.org/ecma-262/6.0/#sec-generatorstart step 4:8 -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150630/2dbe7ea6/attachment-0001.html>
I see. I always considered the last value to be a part of the iteration, but if you don't (and for(of) treats it like that) it makes perfect sense.
I see. I always considered the last value to be a part of the iteration, but if you don't (and for(of) treats it like that) it makes perfect sense. Thanks! Tim On Tue, Jun 30, 2015 at 8:31 PM, Kevin Smith <zenparsing at gmail.com> wrote: > If you use yield instead of return in your generator function you'll get > the desired results. When using a generator function to implement > iteration, you'll generally want to avoid returning a final value, since > for-of ignores the return value. > > The return value does have an important role to play in coroutine-style > use cases. > > On 2:20PM, Tue, Jun 30, 2015 Tim Jansen <ml at tjansen.de> wrote: > >> Hi, >> >> I am working on a collections library that supports the Iterable/Iterator >> protocol, but I ran into a stumbling block: the iterator protocol seems to >> work differently for arrays and generator functions. Array iterators set >> 'done' to true *after* the last element, but function generators set 'done' >> to true *on* the last element. >> >> Is this incompatibility intentional, or or just an implementation issue >> in the browsers (tested on FF38 and Chrome 43)? I wasn't able to find any >> information on this. The ES6 draft from April '15 doesn't define when >> exactly 'done' is set. >> >> >> Code example: >> >> var a = ['a', 'b']; >> >> var itA = a[Symbol.iterator]; >> >> itA.next(); // {value: 'a', done: false} >> >> itA.next(); // {value: 'b', done: false} !! >> >> itA.next(); // {value: undefined, done: true} >> >> >> function* b() { >> >> yield 'a'; >> >> return 'b'; >> >> } >> >> var itB = a[Symbol.iterator]; >> >> itB.next(); // {value: 'a', done: false} >> >> itB.next(); // {value: 'b', done: true} !!! >> >> itB.next(); // {value: undefined, done: true} >> >> The difference is in the second invocation of next(), which returns true >> for generator functions. That protocol makes it impossible for me to >> support both generator functions and array iterators with the same >> implementation - at least if I want to support 'undefined' as a valid value >> in collections. I wouldn't be able to differentiate between an empty list >> ([]) and a list containing undefined ([undefined]). >> >> >> Thanks, >> >> Tim >> >> >> >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150630/9a1db70b/attachment.html>
I am working on a collections library that supports the Iterable/Iterator protocol, but I ran into a stumbling block: the iterator protocol seems to work differently for arrays and generator functions. Array iterators set 'done' to true after the last element, but function generators set 'done' to true on the last element.
Is this incompatibility intentional, or or just an implementation issue in the browsers (tested on FF38 and Chrome 43)? I wasn't able to find any information on this. The ES6 draft from April '15 doesn't define when exactly 'done' is set.
Code example:
var a = ['a', 'b']; var itA = a[Symbol.iterator]; itA.next(); // {value: 'a', done: false} itA.next(); // {value: 'b', done: false} !! itA.next(); // {value: undefined, done: true} function* b() { yield 'a'; return 'b'; } var itB = a[Symbol.iterator]; itB.next(); // {value: 'a', done: false} itB.next(); // {value: 'b', done: true} !!! itB.next(); // {value: undefined, done: true}
The difference is in the second invocation of next(), which returns true for generator functions. That protocol makes it impossible for me to support both generator functions and array iterators with the same implementation - at least if I want to support 'undefined' as a valid value in collections. I wouldn't be able to differentiate between an empty list ([]) and a list containing undefined ([undefined]).