Disallow primitives in `GetIterator()` for async iterables
Normative conversion have been approved for iterables that will no longer be converted from primitives (https://github.com/tc39/how-we-work/pull/152). There is currently no specification for async iterable to be converted from primitives, and the Web IDL converter is currently working on allowing only objects (https://github.com/whatwg/webidl/pull/1397).
I think it would be better to disallow primitives in GetIterator() for async iterables, since it will probably not cause break the web.
From what I can tell, GetIterator is used to get async iterators for for-await-of loops and yield* inside async generators. I'd be surprised if nobody was using either of those with strings. Is there a good reason to try to do this?
The normative conventions are meant to apply as guiding principles for new features going forward. We did not expect them to be able to be applied retroactively to existing features like this.
indeed, (async () => { for await (const x of 'abc') { console.log(x); } })() already works, so i'm not sure how it would be web compatible to change it.
If only 1.a. of GetIterator is changed, it seems to be possible to change it without any problem for strings. However, I am not sure if that change is effective.
- If kind is async, then a. Let method be ? GetMethod(obj, %Symbol.asyncIterator%). b. If method is undefined, then ...
On the topic of the normative conventions, it might be better to reject primitives in Stage 3 Array.fromAsync. cc: @js-choi
However, I am not sure if that change is effective.
Effective at what? What are you trying to achieve? Consistency for how primitives are handled in async iterator taking positions?
Main motivation is that we can prohibit prototype pollution for primitives such as Number.prototype[Symbol.asyncIterator]. It is nonsense to make primitives async iterable.
The proposal here from @petamoriken seems to ask that new built-in APIs that accept async iterable inputs (like Array.fromAsync) reject string inputs.
Regarding Array.fromAsync, I am sympathetic to the dislike of strings as direct iterables or async iterables. But I think that Array.fromAsync unfortunately should continue to accept string inputs as iterables. Consistency between Array.fromAsync and for await of, Array.from, and Iterator.from and AsyncIterator.from is unfortunately more important.
See tc39/proposal-iterator-helpers#250: Iterable.from and AsyncIterable.from were going to prohibit string inputs, but Committee consensus reversed this decision because of the strong relationship between them, for of, and for await of.
Array.fromAsync would likely be the last API that follows the strings-are-directly-iterable mistake. Unless we ever decide to make fromAsync for TypedArrays.
But I think that Array.fromAsync unfortunately should continue to accept string inputs as iterables. Consistency between Array.fromAsync and
for await, Array.from, and Iterator.from and AsyncIterator.from is unfortunately more important.
Make sense.
To give some background, there was a discussion on the WHATWG side that ReadableStream.from should reject primitives, and I was suggested that Array.fromAsync should follow suit, but it ended up accepting string | async iterable<T>. See https://github.com/whatwg/webidl/pull/1397#issuecomment-2612481040.