Skip to content
This repository has been archived by the owner on Jun 20, 2023. It is now read-only.

using await/await using/async using #12

Closed
rbuckton opened this issue Feb 8, 2023 · 5 comments · Fixed by #15
Closed

using await/await using/async using #12

rbuckton opened this issue Feb 8, 2023 · 5 comments · Fixed by #15

Comments

@rbuckton
Copy link
Collaborator

rbuckton commented Feb 8, 2023

In the January, 2023 TC39 plenary session there was a debate on what the final syntax for the asynchronous using declaration should be, given that there are conflicting developer intuitions regarding each potential syntax form.

The three forms currently under consideration are:

  • using await x = y (currently proposed)
  • async using x = y
  • await using x = y

We opted to postpone advancement until the March, 2023 plenary to give some delegates the opportunity to conduct informal surveys to determine which of these options more clearly represented the semantics of the proposal. If there is no clear choice, the proposal will advance to Stage 3 at the March, 2023 plenary using the proposed syntax.

There are pros and cons to each syntax option, which I will summarize below.

using await x = y

The current proposal syntax was chosen prior to the January, 2023 plenary for a number of reasons. The use of the await keyword very clearly indicates an asynchronous interleaving point, much like AwaitExpression and the for-await-of statement. In addition, the using await keyword order was chosen to avoid ambiguity with an await using expression, given that using on its own remains a valid identifier, and that await as a modifier currently only occurs to the right of the statement it modifies (i.e., for await).

However, there is the potential for confusion for code readers due to the non-local nature of the using declaration. The actual await occurs as control flow exits the block scope, rather than immediately at the site of the declaration. This may lead some to incorrectly assume that using await x = y would await the value of x/y. In the case of a for await (const x of y) statement, the for await operation doesn't await the value of y, though it does await the result of each next() operation on its iterator, which in turn means that it does await the value that becomes x. This potential conflation of meanings can lead to confusion if attempting to intuit the meaning of using await given for await as context.

async using x = y

The async using syntax form was initially suggested as a means to pair with a specially annotated await using { ... } block, so as to resolve #1. However, we were able to resolve #1 without the introduction of a new block syntax, which is why we did not choose prior to the January, 2023 plenary.

The advantage of the async using syntax is that it indicates an asynchronous operation without conveying a meaning that the operation might occur immediately. However, async using breaks with existing uses of async in the language today. Currently, async is only used to indicate functions that have different runtime semantics than a normal function, permitting the use of await expressions and the for-await-of statement in the function body. Yet this use doesn't indicate an interleaving point will occur, which breaks from the intended semantics of this proposal. This meaning of async is further reinforced by proposals like async do {}, which would still require an explicit await somewhere to observe the result.

Also, while a minor concern, async using will likely need a cover grammar to disambiguate between an async using declaration and an async using => declaration.

await using x = y

A third option we've discussed outside of plenary would be to use an await using ordering instead. This matches the C# syntax that is the equivalent of this behavior, and has the benefit of continuing to use await to indicate an async interleaving point. This also has a slight advantage over using await, given that the keyword order may lean more towards an interpretation of "await the using of x". It is unclear, however, if this distinction is enough to guide developer intuition.

As with async using, there is a minor concern regarding the need for a potential cover grammar to disambiguate await using as a declaration from await using (or await using.x) as an expression.

Not considered: using async x = y

We are not currently considering a using async keyword order at this time. We feel it is important to align the sync and async versions of the proposal, and are concerned that the ambiguity between:

using async x = y; // async 'using' of 'x' identifier
using async = y; // sync 'using' of 'async' identifier

would lead to further confusion. We could ban async as an identifier in using, as we've currently done for await (and for the same reason), however there is a distinction between await and async as identifiers. Currently, await is a reserved word, making it a syntax error to use it as an identifier in strict-mode code. It is also a syntax error to use it as an identifier in an async function, leaving it as only legal in non-async, non-strict code. async, on the other hand, is not reserved in any mode, nor is it reserved in async functions, so we are concerned that banning async for this purpose would get in the way of potential refactors in existing code, such as:

// source
const async = ...;
try {
  ...
}
finally {
  async.dispose();
}

// refactored
using async_1 = ...;
...

Due to the existing restrictions the language imposes on the use of await as an Identifier, we're far less concerned about using await being a refactoring hazard.

@rbuckton
Copy link
Collaborator Author

rbuckton commented Feb 8, 2023

cc: @syg

@rbuckton
Copy link
Collaborator Author

rbuckton commented Feb 8, 2023

also cc: @mhofman, @erights, @bakkot

@ljharb
Copy link
Member

ljharb commented Feb 8, 2023

Note that async doesn't just involve await, it ensures that the function (or do expression) will produce a Promise and can't ever produce anything else, including a thrown exception. (this statement is not an argument for or against any of the three syntax choices above)

@hax
Copy link
Member

hax commented Mar 19, 2023

@rbuckton We discussed syntax options on last week JSCIG meeting, here is the poll result: https://github.com/JSCIG/es-discuss/blob/master/feedback/202303-async-using.md .

We had 8 respondents, only 1 choose using await, all others choose either async using or await using. Most people feel await/async keyword should be put before using.

@rbuckton
Copy link
Collaborator Author

Per the March plenary, the consensus was to use await using.

Fixed by #15

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants