Proposal: for-of-withas a way to provide a value to the generator

Marius Gundersen gundersen at gmail.com
Wed Aug 23 11:33:12 UTC 2017


The problem with closing an iterator is not just about closing it when it
throws, it's also about closing it when the consumer stops reading early
(for example when you use `break` in a for-of loop). This can be done, as
described in the [article](
http://raganwald.com/2017/07/22/closing-iterables-is-a-leaky-abstraction.html)
I linked to or in the [gist](
https://gist.github.com/mariusGundersen/985189540541189ca80f60b59fa343ac) I
linked to. Both the for-of-with and the continue-with/break-with solutions
will work just as fine with iterators as they will with async-iterators, so
they will both work with async resource handling (this whole thread came
about because I needed this in my own code, for a [for-await-of loop](
https://github.com/es-git/es-git/blob/master/packages/push-mixin/ts/index.ts#L39)
).

I think the continue-with/break-with syntax might be a better solution to
this problem. It's slightly trickier to implement for a transpiler, and it
does not cover the initial next value (but as I said this isn't supported
without the `Function.sent` proposal anyways). The advantage of break-with
is that it works with the `Iterator.return()` method, something the
for-of-with doesn't. For-of loops can already send a value using `throw()`
(by throwing an exception), and using the proposed continue-with and
break-with statements it will also be able to send values using `next()`
and `return()` too.

On Tue, Aug 22, 2017 at 7:08 PM, Isiah Meadows <isiahmeadows at gmail.com>
wrote:

> Edit: the `use` function should be using `result = iter.return()`, not
> `result = func(iter)`. My bad.
> -----
>
> Isiah Meadows
> me at isiahmeadows.com
>
> Looking for web consulting? Or a new website?
> Send me an email and we can get started.
> www.isiahmeadows.com
>
>
> On Tue, Aug 22, 2017 at 12:30 PM, Isiah Meadows <isiahmeadows at gmail.com>
> wrote:
> > Inline:
> >
> >
> > On Tue, Aug 22, 2017 at 3:36 AM, Marius Gundersen <gundersen at gmail.com>
> wrote:
> >> One of the reasons I think for-of should handle this is because of the
> error
> >> handling. [Closing an
> >> iterator](http://raganwald.com/2017/07/22/closing-iterables-is-a-leaky-
> abstraction.html)
> >> is not trivial, and so having to write that code yourself is error
> prone.
> >
> > Very true. Here's how I feel it could be addressed: you could create a
> > utility function to close an iterator after it throws, like this:
> >
> > ```js
> > function use(gen, func) {
> >     const iter = gen[Symbol.iterator]()
> >     let caught, error, result
> >     try {
> >         return result = func(iter)
> >     } catch (e) {
> >         caught = true
> >         error = e
> >     } finally {
> >         try {
> >             iter.return()
> >         } finally {
> >             if (caught) throw error
> >             if (result == null || typeof result !== "object" && typeof
> > result !== "function") {
> >                 throw new TypeError("result must be an object")
> >             }
> >         }
> >     }
> > }
> > ```
> >
> > Ideally, though, we should have some sort of resource management
> > system like what I proposed a while back [1], but that's pretty
> > non-trivial for starters. There's also the issue of I/O being almost
> > always async in idiomatic JS APIs.
> >
> > [1]: https://esdiscuss.org/topic/resource-management
> >
> >>
> >> I originally considered `continue x;` (and `break x;`), but this is
> already
> >> used for labels, but it seems `continue with x;` (and `break with x;`)
> will
> >> work, as the following throws a syntax error today: `with:
> >> while(true){continue with;}`. Only problem as you said Isaiah is that
> you
> >> can't send an initial value, but at least until
> >> [`function.sent`](https://github.com/allenwb/ESideas/
> blob/master/Generator%20metaproperty.md)
> >> proposal is accepted that is not a problem, as there is no way for the
> >> generator to receive the initial `next` value, so it's not really of
> much
> >> value today.
> >
> > Except it kind of is. The iterator protocol *does* include optional
> > `throw` and `return` methods [2], and `IteratorClose(iterator,
> > completion)` uses `return` internally [3].
> >
> > [2]: https://tc39.github.io/ecma262/#sec-iterator-interface
> > [3]: https://tc39.github.io/ecma262/#sec-iteratorclose
> >
> >> And since the `Iterarot.return()` method takes an optional
> >> value as well, it makes sense to have support for `break with x;`
> >
> > -----
> >
> > Isiah Meadows
> > me at isiahmeadows.com
> >
> > Looking for web consulting? Or a new website?
> > Send me an email and we can get started.
> > www.isiahmeadows.com
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170823/85a8feb7/attachment.html>


More information about the es-discuss mailing list