I thought I’d raise a discussion on just what exactly iterators are, a
simple view might be that they’re just a sequence of values which can be
gotten using .next(). However this is simplified because iterators .next
can actually do three things:
They can yield a value
They can return a value
They can throw an error
With these three things in mind how should we actually consume these
things called iterators.
The current methods are (in addition to the await versions in
async-iteration):
The for-of loop but it can only use non-completion values
Manually calling .next e.g. in a while loop
One place I’m aware of all three things being used is in coroutines
(which have two way communication) but are there other places where
errors/returns are actually used for iterators? As an example where I
might consider using both non-completion and completion values in an
iterator is for hinting progress values as an example I’ve actually
written (but using Workers and progress events instead) a library to
generate a Range Minimum Query for a very large array of data, but
suppose we had implemented this using some fictional IterableWorker:
// Inside iterable worker function* createMinQueryTree(data) {
const result = newUint8Array(data.length*2)
const chunkSize = Math.floor(data.length/1000)
for (let i=data.length; i >= 0; i--) {
const leftChild = 2*i + 1const rightChild = 2*i + 2
result[i] = Math.min(data[leftChild], data[rightChild])
if (i % chunkSize === 0) {
yield i/data.length
}
}
return result
}
// Send progress messages somehow ... // Inside main programconst worker = new IterableWorker('./createMinQueryTree.js')
const iter = worker.postMessage(data)[Symbol.iterator]()
let bar = new ProgressBar()
let result
while (true) {
const {done, value} = iter.next()
if (done) { // If done then our value is the result
result = value
break
}
bar.displayProgress(value)
}
bar.dispose() ... // Do stuff with result
Of course this might be an antipattern (if so can someone suggest how
one would actually go about doing something like this), but assuming
this is reasonable it would be far nicer if we had some fictional
construct such as:
const bar = new ProgressBar()
for (let progress of worker.postMessage(data)) {
bar.displayProgress(progress)
} then (result) {
... // Do stuff with result
}
bar.dispose()
We could even extend this construct with catch e.g.
const bar = new ProgressBar()
for (let progress of worker.postMessage(data)) {
bar.displayProgress(progress)
} catch (err) {
doSomethingToRecover(err)
} then (result) {
... // Do stuff with result
} finally {
bar.dispose()
}
Questions I have:
What do people use iterators for other than just data sequences?
What ways are there to represent sequences such as progress that
have a completion value?
Even if the above example is an anti-pattern would the expository
syntax still be useful for other purposes?
If the above example is an anti-pattern what might code for the
above situation look like using Iterators/AsyncIterators and
for-of/for-await-of loops or is this problem fundamentally not
expressible in a clean way using these constructs?
I believe this syntax would cause ambiguity with different styles
e.g. this would be ambiguous
for (let i of it)
{
...
}
then (...) // This would be parsed a function call
{
// Followed by a block ...
}
so what alternatives might there be (else maybe?)?
All other feedback is welcome too.
I thought I’d raise a discussion on just what exactly iterators are, a
simple view might be that they’re just a sequence of values which can be
gotten using .next(). However this is simplified because iterators .next
can actually do three things:
1.
They can yield a value
2.
They can return a value
3.
They can throw an error
With these three things in mind how should we actually consume these
things called iterators.
The current methods are (in addition to the await versions in
async-iteration):
1. The for-of loop but it can only use non-completion values
2. Manually calling .next e.g. in a while loop
One place I’m aware of all three things being used is in coroutines
(which have two way communication) but are there other places where
errors/returns are actually used for iterators? As an example where I
might consider using both non-completion and completion values in an
iterator is for hinting progress values as an example I’ve actually
written (but using Workers and progress events instead) a library to
generate a Range Minimum Query for a very large array of data, but
suppose we had implemented this using some fictional IterableWorker:
|// Inside iterable worker function* createMinQueryTree(data) { const
result = new Uint8Array(data.length*2) const chunkSize =
Math.floor(data.length/1000) for (let i=data.length; i >= 0; i--) {
const leftChild = 2*i + 1 const rightChild = 2*i + 2 result[i] =
Math.min(data[leftChild], data[rightChild]) if (i % chunkSize === 0) {
yield i/data.length } } return result } // Send progress messages
somehow ... // Inside main program const worker = new
IterableWorker('./createMinQueryTree.js') const iter =
worker.postMessage(data)[Symbol.iterator]() bar = new ProgressBar() let
result while (true) { const {done, value} = iter.next() if (done) { //
If done then our value is the result result = value break }
bar.displayProgress(value) } bar.dispose() ... // Do stuff with result |
Of course this might be an antipattern (if so can someone suggest how
one would /actually/ go about doing something like this), but assuming
this is reasonable it would be far nicer if we had some fictional
construct such as:
|const bar = new ProgressBar() for (let progress of
worker.postMessage(data)) { bar.displayProgress(progress) } then
(result) { ... // Do stuff with result } bar.dispose() ... // Do stuff
with result |
We could even extend this construct with catch e.g.
|const bar = new ProgressBar() for (let progress of
worker.postMessage(data)) { bar.displayProgress(progress) } catch (err)
{ doSomethingToRecover(err) } then (result) { ... // Do stuff with
result } finally { bar.dispose() } |
------------------------------------------------------------------------
Questions I have:
* What do people use iterators for other than just data sequences?
* What ways are there to represent sequences such as progress that
have a completion value?
* Even if the above example is an anti-pattern would the expository
syntax still be useful for other purposes?
* If the above example is an anti-pattern what might code for the
above situation look like using Iterators/AsyncIterators and
for-of/for-await-of loops or is this problem fundamentally not
expressible in a clean way using these constructs?
* I believe this syntax would cause ambiguity with different styles
e.g. this would be ambiguous
|for (let i of it) { ... } then (...) // This would be parsed a
function call { // Followed by a block ... } |
so what alternatives might there be (|else| maybe?)?
All other feedback is welcome too.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20161019/4a181a51/attachment-0001.html>
I thought I’d raise a discussion on just what exactly iterators are, a simple view might be that they’re just a sequence of values which can be gotten using .next(). However this is simplified because iterators .next can actually do three things:
They can yield a value
They can return a value
They can throw an error
With these three things in mind how should we actually consume these things called iterators.
The current methods are (in addition to the await versions in async-iteration):
The for-of loop but it can only use non-completion values
Manually calling .next e.g. in a while loop
One place I’m aware of all three things being used is in coroutines (which have two way communication) but are there other places where errors/returns are actually used for iterators? As an example where I might consider using both non-completion and completion values in an iterator is for hinting progress values as an example I’ve actually written (but using Workers and progress events instead) a library to generate a Range Minimum Query for a very large array of data, but suppose we had implemented this using some fictional IterableWorker:
// Inside iterable worker function* createMinQueryTree(data) { const result = new Uint8Array(data.length*2) const chunkSize = Math.floor(data.length/1000) for (let i=data.length; i >= 0; i--) { const leftChild = 2*i + 1 const rightChild = 2*i + 2 result[i] = Math.min(data[leftChild], data[rightChild]) if (i % chunkSize === 0) { yield i/data.length } } return result } // Send progress messages somehow ... // Inside main program const worker = new IterableWorker('./createMinQueryTree.js') const iter = worker.postMessage(data)[Symbol.iterator]() let bar = new ProgressBar() let result while (true) { const {done, value} = iter.next() if (done) { // If done then our value is the result result = value break } bar.displayProgress(value) } bar.dispose() ... // Do stuff with result
Of course this might be an antipattern (if so can someone suggest how one would actually go about doing something like this), but assuming this is reasonable it would be far nicer if we had some fictional construct such as:
const bar = new ProgressBar() for (let progress of worker.postMessage(data)) { bar.displayProgress(progress) } then (result) { ... // Do stuff with result } bar.dispose()
We could even extend this construct with catch e.g.
const bar = new ProgressBar() for (let progress of worker.postMessage(data)) { bar.displayProgress(progress) } catch (err) { doSomethingToRecover(err) } then (result) { ... // Do stuff with result } finally { bar.dispose() }
Questions I have:
What do people use iterators for other than just data sequences?
What ways are there to represent sequences such as progress that have a completion value?
Even if the above example is an anti-pattern would the expository syntax still be useful for other purposes?
If the above example is an anti-pattern what might code for the above situation look like using Iterators/AsyncIterators and for-of/for-await-of loops or is this problem fundamentally not expressible in a clean way using these constructs?
I believe this syntax would cause ambiguity with different styles e.g. this would be ambiguous
for (let i of it) { ... } then (...) // This would be parsed a function call { // Followed by a block ... }
so what alternatives might there be (
else
maybe?)?All other feedback is welcome too.