New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discuss newborn generator TypeError behavior. #25

Merged
merged 1 commit into from Jan 28, 2014

Conversation

Projects
None yet
3 participants
@benjamn
Member

benjamn commented Jan 28, 2014

I would like to establish a convention that

function *wrapper() {
  return yield* delegate;
}

is the best way to create a wrapper generator function around an existing generator object (delegate) such that the generator object created by wrapper() behaves as much like delegate as possible.

This goal of transparent wrapping is inspired by the long-standing JS convention that

function wrapper() {
  return fn.apply(this, arguments);
}

is the best way to create a wrapper function that behaves like fn.

The current specification almost provides this transparency, with one exception: the object created by wrapper() is necessarily a newborn generator, whereas delegate might not be a newborn generator.

I think we might want to relax the language about throwing a TypeError when wrapper().next(value) is called with typeof value !== "undefined", since that value might be of interest to the delegate generator.

Discuss newborn generator TypeError behavior.
I would like to establish a convention that
```js
function *wrapper() {
  return yield* delegate;
}
```
is the best way to create a wrapper generator function around an existing generator object (`delegate`) such that the generator object created by `wrapper()` behaves as much like `delegate` as possible.

This goal of transparent wrapping is inspired by the long-standing JS convention that
```js
function wrapper() {
  return fn.apply(this, arguments);
}
```
is the best way to create a wrapper function that behaves like `fn`.

The current specification _almost_ provides this transparency, with one exception: `delegate` might not be a newborn generator, so I think we might want to relax the language about throwing a `TypeError` when `wrapper().next(value)` is called with `typeof value !== "undefined"`, since that `value` might be of interest to the `delegate` generator.

rwaldron added a commit that referenced this pull request Jan 28, 2014

Merge pull request #25 from benjamn/patch-1
Discuss newborn generator TypeError behavior.

@rwaldron rwaldron merged commit 3093265 into tc39:master Jan 28, 2014

@benjamn

This comment has been minimized.

Show comment
Hide comment
@benjamn

benjamn Jan 28, 2014

Member

A few more concrete thoughts (notes to myself / thinking out loud).

Here is the most idiomatic way I know to achieve the desired semantics of the wrapper function above:

function wrapper() {
  var gen = (function*() {
    // In case we care about the first value sent to the delegate,
    // we need an extra yield to capture that value.
    var sent = yield, info;

    doExtraStuffBeforeDelegate();

    // If delegate is newborn and typeof sent !== "undefined",
    // a TypeError should be thrown here.
    while (!(info = delegate.next(sent)).done) {
      sent = yield info.value;
    }

    doExtraStuffAfterDelegate();

    return info.value;
  })(); // Note the immediate creation of the anonymous wrapper generator.

  // Invoke the wrapper generator once to ensure it is not newborn.
  gen.next();

  return gen;
}

My essential hope is to make the above code much simpler and more idiomatic to write:

function *wrapper() {
  doExtraStuffBeforeDelegate();
  var result = yield* delegate;
  doExtraStuffAfterDelegate();
  return result;
}
Member

benjamn commented Jan 28, 2014

A few more concrete thoughts (notes to myself / thinking out loud).

Here is the most idiomatic way I know to achieve the desired semantics of the wrapper function above:

function wrapper() {
  var gen = (function*() {
    // In case we care about the first value sent to the delegate,
    // we need an extra yield to capture that value.
    var sent = yield, info;

    doExtraStuffBeforeDelegate();

    // If delegate is newborn and typeof sent !== "undefined",
    // a TypeError should be thrown here.
    while (!(info = delegate.next(sent)).done) {
      sent = yield info.value;
    }

    doExtraStuffAfterDelegate();

    return info.value;
  })(); // Note the immediate creation of the anonymous wrapper generator.

  // Invoke the wrapper generator once to ensure it is not newborn.
  gen.next();

  return gen;
}

My essential hope is to make the above code much simpler and more idiomatic to write:

function *wrapper() {
  doExtraStuffBeforeDelegate();
  var result = yield* delegate;
  doExtraStuffAfterDelegate();
  return result;
}

benjamn added a commit to facebook/regenerator that referenced this pull request Jan 28, 2014

@BrendanEich

This comment has been minimized.

Show comment
Hide comment
@BrendanEich

BrendanEich Feb 9, 2014

Contributor

See http://esdiscuss.org/notes/2014-01-28#more-generators-ben- toward end:

Waldemar Horwat: There are two problems here:

  1. A function* can't capture the first value passed to the next that invoked it. Instead, it currently requires it to be undefined.
  2. No way to pass an initial next value to yield*. This means that manually doing the first yield followed by a yield* wouldn't help because the problem would then reappear on the second yield.

Waldemar Horwat: The proposal is proposing a hidden channel (a la Perl's $_) that ties 1 to 2 here. Would prefer mechanisms to do those separately and more explicitly.

Ben Newman: yield syntax that says delegate but don't care about value?

Dave Herman: Let's think about it more...

Dave Herman: Went through the mental excercise to do an implicit yield upon calling the generator. Leads to a lot of other issues.

function*() first {
  return yield* push(first, delegate);
}

Concensus/Resolution

  • Ben Newman: Have to go back and think more about this. Maybe a helper function can be created.

/be

Contributor

BrendanEich commented Feb 9, 2014

See http://esdiscuss.org/notes/2014-01-28#more-generators-ben- toward end:

Waldemar Horwat: There are two problems here:

  1. A function* can't capture the first value passed to the next that invoked it. Instead, it currently requires it to be undefined.
  2. No way to pass an initial next value to yield*. This means that manually doing the first yield followed by a yield* wouldn't help because the problem would then reappear on the second yield.

Waldemar Horwat: The proposal is proposing a hidden channel (a la Perl's $_) that ties 1 to 2 here. Would prefer mechanisms to do those separately and more explicitly.

Ben Newman: yield syntax that says delegate but don't care about value?

Dave Herman: Let's think about it more...

Dave Herman: Went through the mental excercise to do an implicit yield upon calling the generator. Leads to a lot of other issues.

function*() first {
  return yield* push(first, delegate);
}

Concensus/Resolution

  • Ben Newman: Have to go back and think more about this. Maybe a helper function can be created.

/be

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment