I've seen different syntax suggestions related to async disposal spread over different issues, in particular tc39/proposal-explicit-resource-management#16 tc39/proposal-explicit-resource-management#76 tc39/proposal-explicit-resource-management#84 #4. I wanted to concentrate the discussion in a single issue.
I'd first like to discuss the ongoing assumption that using an async-disposable requires specific syntax.
The way I model the using syntax is that a block containing a using declaration implicitly creates a DisposableStack. Every using declaration implicitly results in a .use() on the stack, and that exiting the block implicitly calls [Symbol.dispose]() on the stack.
Now if we assume that we have a concept of "async blocks", instead of a DisposableStack being implicitly created, it'd be an AsyncDisposableStack. At that point any using declaration would similarly call the .use() of the implicit async disposable stack, which is a synchronous operation, and it's the exit of the "async block" which awaits the [Symbol.asyncDispose]() call.
As such I would be against any syntax that uses the await keyword for the using declaration, as nothing is awaited at the declaration time. Similarly I would be against any syntax that doesn't use the await keyword on the block as a marker of interleaving. I would be ok with a async using declaration to be explicit, but I would consider that unnecessary verbosity.
Given the mental model above, I believe it would be entirely natural that for await (using r of ...), and using declarations inside for-await-of blocks in general, would implicitly use an AsyncDisposableStack. for-await-of is conceptually the only "async block" in the language at the moment. Then it become a matter of specifying what the syntax of an "async block" not tied to iteration looks like.
I've seen different syntax suggestions related to async disposal spread over different issues, in particular tc39/proposal-explicit-resource-management#16 tc39/proposal-explicit-resource-management#76 tc39/proposal-explicit-resource-management#84 #4. I wanted to concentrate the discussion in a single issue.
I'd first like to discuss the ongoing assumption that
usingan async-disposable requires specific syntax.The way I model the
usingsyntax is that a block containing ausingdeclaration implicitly creates aDisposableStack. Everyusingdeclaration implicitly results in a.use()on the stack, and that exiting the block implicitly calls[Symbol.dispose]()on the stack.Now if we assume that we have a concept of "async blocks", instead of a
DisposableStackbeing implicitly created, it'd be anAsyncDisposableStack. At that point anyusingdeclaration would similarly call the.use()of the implicit async disposable stack, which is a synchronous operation, and it's the exit of the "async block" which awaits the[Symbol.asyncDispose]()call.As such I would be against any syntax that uses the
awaitkeyword for theusingdeclaration, as nothing is awaited at the declaration time. Similarly I would be against any syntax that doesn't use theawaitkeyword on the block as a marker of interleaving. I would be ok with aasync usingdeclaration to be explicit, but I would consider that unnecessary verbosity.Given the mental model above, I believe it would be entirely natural that
for await (using r of ...), andusingdeclarations insidefor-await-ofblocks in general, would implicitly use anAsyncDisposableStack.for-await-ofis conceptually the only "async block" in the language at the moment. Then it become a matter of specifying what the syntax of an "async block" not tied to iteration looks like.