Skip to content

Instantly share code, notes, and snippets.

@withoutboats withoutboats/for-await.md
Last active Apr 3, 2019

Embed
What would you like to do?

Considerations for writing a loop over a Stream as it relates to await syntax.

JavaScript uses this syntax:

for await (elem of stream) {
   // ...
}

It makes sense to use await in the syntax (as opposed to async), because its an await point.

All syntaxes we're considering present some problems. Note that this is a part of the loop syntax, not the pattern. A stream is not equivalent to an iterator of futures because the future lifetimes are tied to the borrow in next (though the output of the future currently cannot be).

I think (unsurprisingly) this syntax favors prefix. At very least I think it favors a space based syntax. Its hard for me to imagine a syntax like:

for elem.await in stream

When the .await is not a part of the pattern construction. Maybe other people differ. (I would find even odder the method and macro like postfix syntaxes, since they are very clearly intended to mimic expressions and this is not an expression at all).

However, even the prefix syntax has some quirks. If we had both await and await?, we'd probably want both to work here as well:

for await? elem in stream

On the face of it, this is fine. However, there is an interesting quirk if we ever allow ? in patterns, as we've long discussed. That would make this valid:

for await elem? in stream

Unlike expressions, this actually works and does what the user wants (that is, it awaits and then ?s). So in this position for await? elem and for await elem? would mean the same thing, whereas in an expression context they don't.

I'm assuming that we consider at least some degree of syntactic consistency between await expressions and stream loops a virtue. There's an argument to be made that if they can't be completely consistent they should be highly inconsistent (which would favor combining a postfix expression syntax with the prefix loop syntax).

Since syntaxes like .await are abandoning a lot of precedent, we could do something really unorthodox like this and have the .await be applied to the for keyword:

for.await elem in stream
@withoutboats

This comment has been minimized.

Copy link
Owner Author

withoutboats commented Apr 3, 2019

Follow up comment on this point:

Note that this is a part of the loop syntax, not the pattern. A stream is not equivalent to an iterator of futures because the future lifetimes are tied to the borrow in next (though the output of the future currently cannot be).

Streams are equivalent to a streaming iterator of future, that is, roughly this impl is plausible:

impl<S: Stream> StreamingIterator for S {
     type Item<'a> = futures::stream::Next<'a, S>; // Next<'a, S>: Future<Output = S::Item>
}

So an alternative option would be to find a way that for loops can be backwards compatibly extended to work on streaming iterators, make await (as well as ?) a part of the pattern syntax, and just treat all streams as streaming iterators of futures.

Doing this I think would have no impact on prefix/postfix, because both could be made to work consistently with the way they work in expressions (by defining the same precedence).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.