Re: [whatwg/webidl] Add `async iterable<T>` type to WebIDL (PR #1397)

@MattiasBuelens commented on this pull request.

Looks pretty good! I still have a question about what it really means to "convert an IDL async iterable value to a JavaScript object" though, see below.

> +
+IDL <a lt="async iterable type">async iterable&lt;|T|&gt;</a> values are represented by a JavaScript
+object and a JavaScript [=Iterator=] record.
+
+<div id="js-to-async-iterable" algorithm="convert a JavaScript value to async iterable">
+    A JavaScript value |V| is [=converted to an IDL value|converted=]
+    to an IDL <a lt="async iterable type">async iterable&lt;<var ignore>T</var>&gt;</a> value as follows:
+
+    1.  If <a abstract-op>Type</a>(|V|) is not Object,
+        [=JavaScript/throw=] a <l spec=ecmascript>{{TypeError}}</l>.
+    1.  Let |iteratorRecord| be [=?=] <a abstract-op>GetIterator</a>(|V|, async).
+    1.  Return |iteratorRecord|.
+</div>
+
+<div id="async-iterable-to-js" algorithm="convert an async iterable to a JavaScript value">
+    An IDL <a lt="async iterable type">async iterable&lt;|<var ignore>T</var>&gt;</a> value is

Typo:
```suggestion
    An IDL <a lt="async iterable type">async iterable&lt;<var ignore>T</var>&gt;</a> value is
```

> @@ -11174,6 +11347,23 @@ Note: The HTML Standard defines how a security check is performed. [[!HTML]]
         1.  Otherwise: if <a abstract-op>Type</a>(|V|) is Object and
             there is an entry in |S| that has one of the
             following types at position |i| of its type list,
+            *   a [=async iterable type=]

```suggestion
            *   an [=async iterable type=]
```

> +            *   a [=nullable type|nullable=] version of any of the above types
+            *   an [=annotated type=] whose [=annotated types/inner type=] is one of the above types
+            *   a [=union type=], [=nullable type|nullable=] union type, or [=annotated type|annotated=] union type
+                that has one of the above types in its [=flattened member types=]
+
+            and after performing the following steps,
+
+            1.  Let |method| be [=?=] <a abstract-op>GetMethod</a>(|V|, {{@@asyncIterator}}).
+
+            |method| is not <emu-val>undefined</emu-val>, then remove from |S| all
+            other entries.
+
+        1.  Otherwise: if <a abstract-op>Type</a>(|V|) is Object and
+            there is an entry in |S| that has one of the
+            following types at position |i| of its type list,
+            *   a [=async iterable type=]

```suggestion
            *   an [=async iterable type=]
```

> @@ -11342,11 +11532,11 @@ Note: The HTML Standard defines how a security check is performed. [[!HTML]]
     Generally, the inspection of the value at the distinguishing argument index does not have any
     side effects, and the only side effects in the overload resolution algorithm are the result of
     converting the JavaScript values to IDL values.
-    (An exception exists when one of the overloads has a [=sequence type=] or [=frozen array type=]
-    at the distinguishing argument index.
-    In this case, we attempt to get the {{@@iterator}} property to determine the appropriate
-    overload, and perform the conversion of the distinguishing argument separately before continuing
-    with the next step.)
+    (An exception exists when one of the overloads has a [=async iterable type=], [=sequence type=]

```suggestion
    (An exception exists when one of the overloads has an [=async iterable type=], [=sequence type=]
```

> @@ -8064,6 +8119,124 @@ JavaScript Array values.
 </div>
 
 
+<h4 id="js-async-iterable">Async iterable — async iterable&lt;|T|&gt;</h4>
+
+IDL <a lt="async iterable type">async iterable&lt;|T|&gt;</a> values are represented by a JavaScript
+object and a JavaScript [=Iterator=] record.
+
+<div id="js-to-async-iterable" algorithm="convert a JavaScript value to async iterable">
+    A JavaScript value |V| is [=converted to an IDL value|converted=]
+    to an IDL <a lt="async iterable type">async iterable&lt;<var ignore>T</var>&gt;</a> value as follows:
+
+    1.  If <a abstract-op>Type</a>(|V|) is not Object,
+        [=JavaScript/throw=] a <l spec=ecmascript>{{TypeError}}</l>.
+    1.  Let |iteratorRecord| be [=?=] <a abstract-op>GetIterator</a>(|V|, async).
+    1.  Return |iteratorRecord|.

Consider making this more explicit:
```suggestion
    1.  Return the IDL async iterable value that represents a reference to the JavaScript object |V| and the JavaScript [=Iterator=] record |iteratorRecord|.
```

> +<div id="async-iterable-to-js" algorithm="convert an async iterable to a JavaScript value">
+    An IDL <a lt="async iterable type">async iterable&lt;|<var ignore>T</var>&gt;</a> value is
+    [=converted to a JavaScript value|converted=] to a JavaScript object as follows:
+
+    1.  Return the JavaScript object that represents the same async iterable as the IDL value.
+</div>

When would we need this? If I understand correctly, IDL interfaces should always add an async iterable declaration to themselves, rather than returning an async iterable from one of its operations.

Also, if the async iterable value can only have been created by converting it from a JavaScript value, is this value still usable when converting it back to a JavaScript value? The previous algorithm calls `GetIterator(V, async)`, which for a `ReadableStream` *locks the stream*. When we return the `ReadableStream` back to JavaScript, it'll still be locked by IDL and JavaScript won't be able to async-iterate the stream.

Would it be an option for us to just *disallow* converting an IDL async iterable type back to a JavaScript value?

-- 
Reply to this email directly or view it on GitHub:
https://github.com/whatwg/webidl/pull/1397#pullrequestreview-2183552031
You are receiving this because you are subscribed to this thread.

Message ID: <whatwg/webidl/pull/1397/review/2183552031@github.com>

Received on Wednesday, 17 July 2024 17:53:35 UTC