Skip to content
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

Make the Iterator prototype have its own constructor #730

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

nikolaybotev
Copy link

@nikolaybotev nikolaybotev commented Sep 13, 2024

This change makes the generator prototype chain fully conformant with the spec the Iterator Helpers stage 3 proposal, and enables the following code to work when transpiled to older runtimes:

const Iterator = Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf((function* (){})()))).constructor;

// Add an iterator helper
Iterator.prototype.forEach = function() { /* ... */ }

// Make a custom Iterator class
class RepeatIterator extends Iterator { next() { return { value: 42 } } }

// The iterator helper is available here!
new RepeatIterator().forEach();

Of course, the above already works, but since Iterator.prototype currently returns the global Object prototype, installing forEach installs on all objects, which is not the intent, and RepeatIterator is not able to function as an Iterable, because it does not have the [Symbol.iterator] method. So, notably, with this PR, this will work as well:

for (const n of new RepeatIterator()) {
  console.log(n);
  break;
}
// prints 42

Also, note the above already works if regenerator is used in a standard configuration with preset-env in babel and core-js 3 is required (which polyfills the Iterator constructor, and regenerator picks that up as the "native" Iterator prototype), however, regenerator is already almost fully compliant with the prototype chain spec for generators, and I figured it is good for completeness to add this here, as maybe there are cases where regenerator is not used in that combination with the latest core-js that supplies a proper Iterator constructor implementation.

Unit tests have been added.

Addendum

4A282A55-0B66-42A1-A217-65EF493BE58C

I also went ahead and merged GeneratorFunctionPrototype into Generator, because the two were duplicates -- Generator is the prototype of GeneratorFunction! GeneratorFunctionPrototype was actually the one that was fully setup and Generator was not referenced anywhere in the prototype+constructor chain, except it had its own prototype property set , which allowed it to be used in an instanceof test. That test looks at Generator.prototype only, and because both Generator.prototype and GeneratorFunctionPrototype.prototype were set to the same GeneratorPrototype object, both Generator and GeneratorFunctionPrototype are interchangeable in this position!

In the graphic you can see GFP (GeneratorFunctionPrototype in the code) as the object properly setup in the prototype chain and Generator is crossed out. You can think of the change as a two-step - 1) remove Generator, 2) rename GeneratorFunctionPrototype to Generator.

@facebook-github-bot
Copy link

Hi @nikolaybotev!

Thank you for your pull request and welcome to our community.

Action Required

In order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you.

Process

In order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA.

Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with CLA signed. The tagging process may take up to 1 hour after signing. Please give it that time before contacting us about it.

If you have received this in error or have any questions, please contact us at [email protected]. Thanks!

@nikolaybotev nikolaybotev force-pushed the iterator-prototype-is-iterator-class branch from 554363e to 232e545 Compare September 13, 2024 12:58
@facebook-github-bot
Copy link

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks!

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

Successfully merging this pull request may close these issues.

2 participants