Forwarding `return()` in generators

Axel Rauschmayer axel at rauschma.de
Wed Mar 25 16:24:45 UTC 2015


Good point, if it is about iteration, only `return()` needs to be propagated.

> On 24 Mar 2015, at 23:35, Ron Buckton <Ron.Buckton at microsoft.com> wrote:
> 
> Is your goal to wrap a generator, as it seems you are propagating the exception of the caller by calling iterator.throw(). However, you do not seem to be propagating the sent value, so the protocol here isn’t fully implmeneted.
>  
> If you just want to iterate values (and don’t really care about the return value of the iterable or propagating a thrown exception, you could write:
>  
> ```js
> function* take(n, iterable) {
>   n |= 0;
>   if (n <= 0) {
>     return;
>   }
>   // let for..of call return()
>   for (let value of iterable) {
>     yield value;
>     if (n-- <= 0) {
>       return;
>     }
>   }
> }
> ```
>  
> If you want to support the full communication channel of a generator, you could write:
>  
> ```js
> function* take(n, iterable) {
>   let iterator = iterable[Symbol.iterator]();
>   let step = () => iterator.next();
>   n |= 0;
>   // try..finally outside of loop
>   try {
>     let sent;
>     while (n > 0) {
>       let { value, done } = step();
>       if (done) {
>         return value;
>       }
>       n--;
>       // try..catch local to the yield
>       try {
>         sent = yield value;
>         step = () => iterator.next(sent);
>       }
>       catch (e) {
>         if (typeof iterator.throw === "function") {
>           step = () => iterator.throw(e);
>         }
>         else {
>           throw e;
>         }
>       }
>     }
>   }
>   finally {
>     if (typeof iterator.return === "function") {
>       iterator.return();
>     }
>   }
> }
> ```
>  
> From: es-discuss [mailto:es-discuss-bounces at mozilla.org <mailto:es-discuss-bounces at mozilla.org>] On Behalf Of Axel Rauschmayer
> Sent: Tuesday, March 24, 2015 2:28 PM
> To: Bergi
> Cc: es-discuss list
> Subject: Re: Forwarding `return()` in generators
>  
> Right, it doesn’t look like one needs to know the returned value when forwarding `return()`.
>  
> But: you need to guard against other ways of reaching `finally`. Maybe like this:
>  
> ```js
> function* take(n, iterable) {
>     let iterator = iterable[Symbol.iterator]();
>     n = +n; // make sure it's a number, so that n>0 does never throw
>     let forwardReturn = true;
>     try {
>         while (n > 0) {
>             let item = iterator.next();
>             if (item.done) {
>                 forwardReturn = false;
>                 return item.value;
>             }
>             yield item.value;
>             n--;
>         }
>         forwardReturn = false;
>     } catch (e) {
>         forwardReturn = false;
>         iterator.throw(e);
>     } finally {
>         if (forwardReturn) {
>             iterator.return();
>         }
>     }
> }
> ```
> The above code also has the additional nice property that it call `.return()` on the iterator when `n` values have been taken out of it.
>  
> That’s not what all the other constructs in ES6 do: they only call `return()` if iteration stops abruptly.
>  
> Also missing from this code: checking whether the iterator actually has the methods `return()` and `throw()` and responding accordingly.


-- 
Dr. Axel Rauschmayer
axel at rauschma.de
rauschma.de



-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150325/c2e93123/attachment-0001.html>


More information about the es-discuss mailing list