sdk
sdk copied to clipboard
[dart:js_interop] Support Generators and Iterators
JavaScript has the notion of Iterators and Generators, which allow sequential generation and access to elements in a collection without exposing the collection's internal structure.
Some links:
function*syntax: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*- Generator type: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator
- Iterator protocol: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterator_protocol
Currently, generating interop for a Generator function would require having to:
- Create an extension type for the
Generatortype - Write JS interop for the generator function, and possibly lose out on the powerful features it has
This issue aims to address at least one of the following:
- Adding support for a
JSGeneratorandJSIteratortype: This issue proposes the addition of theJSGeneratorextension type and aJSIteratorextension type (JSGeneratorbuilds on top of, and extendsJSIterator). This allows for not having to unnecessarily reimplement global JS types in different codebases. Instead, it would be better if they were core types in the Dart JS Interop library. Even ifJSGeneratorisn't viable, having aJSIteratortype can help, especially when users may want to use such iterators fromJSArray. - Add support for mapping JS Generator Functions to Dart Generator Functions: Dart also has a similar notion of Generator functions through the use of
sync*andasync*mapped withyieldand/oryield*
It would be nice if Generator functions could be mapped from JS to Dart Generator functions (similar to how asynchronous functions in JS are mapped to Dart asynchronous functions). This can help for users to be able to leverage Dart's sound typing when needed (mapping the iterator type in Dart toIterable<String> list() sync* { for (var i = 0; i < 4; i++) { yield i.toString(); } }JSIterator, for instance), and still be able to fall back to JS's way of doing things if they want
(similar to how asynchronous functions in JS are mapped to Dart asynchronous functions)
I don't think we actually have this. Do we? There is no automatic conversion between Future and Promise, you need to convert them manually.
Add support for mapping JS Generator Functions to Dart Generator Functions
I think it is worth avoiding confusion about this. Modifiers like sync*, async and async* are modifiers on the implementation (e.g. body of the function), they are not part of the signature. What really matters is the return type. The same applies to function* and async function in JavaScript.
So when you want to expose an async function from JS to Dart it is not about the fact that JS has async function and Dart has async modifier and they are kinda similar. It is simply about converting JS Promise produced by async function when it is called to a Dart Future. (Or in other direction).
The same applies to function* and sync* - it is about converting JS Generator object produced by function* to Dart's Iterable. It is also worth keeping in mind that JS Generator has features which are not in Dart's Iterable (e.g. you can pass values into generator when resuming it after yield, there is support for abruptly stopping generator via either return or throw).` - which might be relevant for interop in the other direction (e.g. binding some JS APIs which accept generators and use them in fancy ways).
I don't think we actually have this. Do we? There is no automatic conversion between
FutureandPromise, you need to convert them manually.
Sorry, meant something similar to the manual conversion. There is no automatic conversion.
It is also worth keeping in mind that JS
Generatorhas features which are not in Dart'sIterable(e.g. you can pass values into generator when resuming it after yield, there is support for abruptly stopping generator via eitherreturnorthrow).
Won't it then be possible to have some Dart implementation for this that extends/implements Iterable that would be a suitable wrapper for the JS Generator iterator type? Then similar properties can be shared between Generator and AsyncGenerator.
Won't it then be possible to have some Dart implementation for this that extends/implements
Iterablethat would be a suitable wrapper for the JSGeneratoriterator type? Then similar properties can be shared betweenGeneratorandAsyncGenerator.
Yep, I think it should be possible to provide Iterable implementation which wraps Generator and Stream implementation that wraps AsyncGenerator.
Similar request for Iterator: https://github.com/dart-lang/sdk/issues/53532. I believe making JSIterator and JSGenerator generic would allow us to support async iterators and async generators as well using the same JS type definitions (the generic could just be JSPromise<...>), but the conversions to Iterable and Stream may necessitate we have a separate JSAsyncGenerator type instead of conflating the two.
I believe making
JSIteratorandJSGeneratorgeneric would allow us to support async iterators and async generators as well using the same JS type definitions (the generic could just beJSPromise<...>) ...but the conversions to Iterable and Stream may necessitate we have a separate JSAsyncGenerator type instead of conflating the two.
I think there is an AsyncGenerator and AsyncIterator type. I don't think there are any extra properties or features to them that would be outside having a generic version of them.
Also, would this mean modifying built in iterables already supported (like String, Array, TypedArray), or would those be better off untouched?
Without this type and convertible behavior, I can only use JSArray.from to convert, using JSObject to receive JSIterator.