One of the constraints imposed within TC39 is that calling into some third-party should be guaranteed to not mess up with your state. This heavily influenced the design of the proposal, since the only way to change the async context (`.run`) is guaranteed to clean up after itself.
There is however a significant design of DX improvements, since having to wrap your code in a callback to change its context adds friction. To do this while respecting the constraints that are limiting possible design direction, any mechanism that lets the async context flow "towards the outside" (from a call/promise to its caller) needs to be opt-in:
```javascript
function fn() {
thirdParty() and continue in its context;
}
```
`and continue in its context` is obviously not a resaonable syntax marker that we are going to use, but there have been two concrete suggestions: `await` and `using`:
```javascript
function fn() {
// allows the context to flow out of thirdParty
await thirdParty();
}
```
or
```javascript
function fn() {
// thirdParty returns a disposable that sets and cleans up the context
using _ = thirdParty();
}
```
I have a very strong preference for `using`, for the following reasons:
- `await` is a too weak signal for opting in. Wanting the context to flow out of `await` is the exception, and `await` is way too common for it. We would also need to then define how to use `await` _without_ opting in in this alternative behavior.
- `using` has been designed to "prepare something, and then clean it up at the end of the scope". It matched the `.run` semantics, without forcing developers to use a callback.
The way I see `using` working in this case is that `thirdParty` returns an object similar to:
```javascript
{
get [Symbol.dispose]() {
const oldContext = AsyncContextSwap(newContext);
return () => AsyncContextSwap(oldContext);
}
}
```
That object can be created using some method on `AsyncContext.prototype`, e.g.:
```javascript
function thirdParty() {
return myVar.with("foo");
}
```
There are however some restrictions that we will have to put in place:
- to avoid third-party code to abuse this meahcnism to set the context without then ever cleaning it up, it needs to be something that can _only_ be called by `using` and not manually. i.e. you shouldn't be able to do `myVar.with("foo")[Symbol.dispose]`. Maybe `using` needs to have a special case for those objects, checking an internal slot, and without actually exposing the `[Symbol.dispose]` to userland.
- ideally it needs to work with membranes, or when wrapped in a proxy. This goal is mostly contraddicting the point above, but these two requirements would come from the same people. Maybe the result of `myVar.with("foo")` should be a frozen object, so that it can be used on both sides of the membrane.