Re: [heycam/webidl] Add async_iterable support (#720)

domenic commented on this pull request.

Overall LGTM! A few clarity suggestions.

> +being iterated over asynchronously to obtain a sequence of values.
+
+Note: In the ECMAScript language binding, an interface that is asynchronously iterable will have
+<code class="idl">entries</code>, <code class="idl">keys</code>, <code class="idl">values</code>,
+and {{@@asyncIterator}} properties on its [=interface prototype object=].
+
+Prose accompanying an [=interface=] with an [=asynchronously iterable declaration=] must define a
+<dfn id="dfn-get-the-next-iteration-result">get the next iteration result</dfn> algorithm.
+This algorithm receives a <b>[=this=]</b> value, which is an instance of the [=interface=] that it
+is defined for, and the <dfn export>current state</dfn>.
+It must return a {{Promise}} that either resolves with undefined – to signal the end of the
+iteration – or a tuple with three elements:
+
+1.  a value of the first type given in the declaration;
+1.  a value of the second type given in the declaration;
+1.  an opaque value that is passed back to the next invocation of the algorithm,

Can we omit the opaque value, and have people just store any relevant state on their `this`?

> @@ -11577,6 +11725,45 @@ and the String "<code>values</code>"
 if the interface has a [=setlike declaration=].
 
 
+<h5 id="es-async-iterator">@@asyncIterator</h5>
+
+If the [=interface=] has an [=asynchronously iterable declaration=], then a property must exist
+whose name is the {{@@asyncIterator}} symbol, with attributes
+{ \[[Writable]]: <emu-val>true</emu-val>, \[[Enumerable]]: <emu-val>false</emu-val>, \[[Configurable]]: <emu-val>true</emu-val> }
+and whose value is a [=function object=].
+
+The location of the property is determined as follows:
+
+*   If the interface was declared with the [{{Global}}] [=extended attribute=],
+    then the property exists on the single object that [=implements=] the interface.
+*   Otherwise, the property exists solely on the interface’s [=interface prototype object=].

Kind of sad to add to the declaratively-added properties list, but oh well, this is probably easier for now.

> +An [=interface=] must not have more than one [=asynchronously iterable declaration=].
+The [=inherited interfaces=] of an [=interface=] with an [=asynchronously iterable declaration=]
+must not also have an [=asynchronously iterable declaration=].
+An [=interface=] with an [=asynchronously iterable declaration=] and its [=inherited interfaces=]
+must not have a [=maplike declaration=], [=setlike declaration=], or [=iterable declaration=].
+
+The following extended attributes are applicable to [=asynchronously iterable declarations=]:
+[{{Exposed}}],
+[{{SecureContext}}].
+
+Issue: these [=extended attributes=] are not currently taken into account.
+When they are, the effect will be as you would expect.
+
+<pre class="grammar" id="prod-AsyncIterable">
+    AsyncIterable :
+        "async_iterable" "&lt;" TypeWithExtendedAttributes "," TypeWithExtendedAttributes "&gt;" ";"

Streams will also need some side effects on acquiring the iterator (i.e. calling the function)

> +It serves as the prototype for [=default asynchronous iterator objects=] for the interface.
+
+The \[[Prototype]] [=internal slot=] of an [=asynchronous iterator prototype object=] must be
+{{%AsyncIteratorPrototype%}}.
+
+<div algorithm="to invoke the next property of asynchronous iterators">
+
+    An [=asynchronous iterator prototype object=] must have a <code class="idl">next</code> data
+    property with attributes
+    { \[[Writable]]: <emu-val>true</emu-val>, \[[Enumerable]]: <emu-val>true</emu-val>, \[[Configurable]]: <emu-val>true</emu-val> }
+    and whose value is a [=built-in function object=] that behaves as follows:
+
+    1.  Let |interface| be the [=interface=] for which the
+        [=asynchronous iterator prototype object=] exists.
+
+    1.  Let |thisValidationPromiseCapability| be [=!=] [$NewPromiseCapability$]({{%Promise%}}).

If we had a PromiseReject abstract op, you could just create and return a new promise inline each time. I guess we'd wait for #490 for that.

>  </div>
 
 The [=class string=] of an [=iterator prototype object=] for a given [=interface=]
 is the result of concatenating the [=identifier=] of the [=interface=]
 and the string "<code> Iterator</code>".
 
 
+<h5 id="es-default-asynchronous-iterator-object">Default asynchronous iterator objects</h5>
+
+A <dfn id="dfn-default-asynchronous-iterator-object" export>default asynchronous iterator object</dfn>
+for a given [=interface=], target and iteration kind is an object whose \[[Prototype]]
+[=internal slot=] is the [=asynchronous iterator prototype object=] for the [=interface=].
+
+A [=default asynchronous iterator object=] has internal values:
+
+*   its <em>target</em>, which is an object whose values are to be iterated,

Can we made these dfns, and cross-link to them?

> +    1.  If |object|'s ongoing promise is not undefined, then:
+        1.  Let |afterOngoingPromiseCapability| be [=!=] [$NewPromiseCapability$]({{%Promise%}}).
+        1.  Let |onFulfilled| be [=!=] [$CreateBuiltinFunction$](|nextSteps|, « »).
+        1.  Perform [=!=] [$PerformPromiseThen$](|object|'s ongoing promise, |onFulfilled|,
+            <emu-val>undefined</emu-val>, |afterOngoingPromiseCapability|).
+        1.  Set |object|'s ongoing promise to |afterOngoingPromiseCapability|.\[[Promise]].
+
+    1.  Otherwise:
+        1.  Run |nextSteps| and set |object|'s ongoing promise to the result.
+
+    1.  Return |object|'s ongoing promise.
+</div>
+
+Issue: The [=class string=] of an [=asynchronous iterator prototype object=] for a given
+[=interface=] is the result of concatenating the [=identifier=] of the [=interface=] and the string
+"<code> Iterator</code>".

I guess `" AsyncIterator"`?

> +being iterated over asynchronously to obtain a sequence of values.
+
+Note: In the ECMAScript language binding, an interface that is asynchronously iterable will have
+<code class="idl">entries</code>, <code class="idl">keys</code>, <code class="idl">values</code>,
+and {{@@asyncIterator}} properties on its [=interface prototype object=].
+
+Prose accompanying an [=interface=] with an [=asynchronously iterable declaration=] must define a
+<dfn id="dfn-get-the-next-iteration-result">get the next iteration result</dfn> algorithm.
+This algorithm receives a <b>[=this=]</b> value, which is an instance of the [=interface=] that it
+is defined for, and the <dfn export>current state</dfn>.
+It must return a {{Promise}} that either resolves with undefined – to signal the end of the
+iteration – or a tuple with three elements:
+
+1.  a value of the first type given in the declaration;
+1.  a value of the second type given in the declaration;
+1.  an opaque value that is passed back to the next invocation of the algorithm,

Oh, I see we cannot, because it needs to be *per iterator instance*, not *per interface instance*. Can you add an explanation to that effect?

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

Received on Tuesday, 21 May 2019 18:54:16 UTC