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-boun...@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
a...@rauschma.de<mailto:a...@rauschma.de>
rauschma.de


_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to