[Pitch #2] Async/await

Thank you for the clarification, I think I understand what you're going for here: you don't want actor isolation to be broken by inout parameters. I've been trying to really grok how this works with the proposed model, but I don't think I've really succeeded.

There are two different but confusingly similar concerns that I'm trying to come to grips with:

  1. Actor isolation doesn't want references to state to be transferred across actor boundaries in a way that can introduce race conditions / unsafety. Getting this right is a key part of the actor model design, related to the global semantic discussions, actor sendable, etc.

  2. The "reentrancy" aspect of actors combined with the "opening of accesses in inout parameters" means that things passed as inout parameters can have their accessed opened for "a long time" and cause unexpected exclusivity failures that turn into dynamic crashes that may be difficult to test. This can cause unpredictable and difficult to debug crashes in the field.

If I understand correctly you're trying to solve both problems at the same type by preventing forming inout argument references to properties of actors, e.g. limiting inout binding to local variables.

However, I'm not sure (said differently: every time I think about this I confuse myself :) that this is either necessary or sufficient. Here's my uncertainty:

  • Insufficient: Local variables are part of the actor protected state. They can escape locally in the actor when captured by-ref in a closure. Passing it as an inout argument can cause a race condition between the actors thread/queue/context and the receiving actor's thread. I suppose this would get caught dynamically as an exclusive access violation, but it provokes the second issue above.

  • Necessary: actors can have non-actor crossing sync and async methods within their concurrency domain. It should be perfectly fine to pass actor properties as inout parameters to these intra-actor functions. For example, my understanding of your rule is that no call to a mutating async method on an actor property would be allowed.


I'm primarily concerned about the cross-actor usage of inout parameters from a memory safety perspective. I don't see any obvious way to make this work well, because inout intentionally introducing aliases of actor-protected state in the cross-actor condition.

However, I think the secondary issue is a pretty significant one in practice as well. Even if dynamic exclusivity checks catch the problem if/when the problem manifests in practice, these crashes will be rare, require specific concurrency patterns to manifest, and therefore lead to bugs in practice.

This also doesn't seem like an important case to support for expressivity, so I'd prefer to define away the foot gun and complexity entirely.


Concrete proposal / recommendation / thought:

The compiler already has to reason about cross-actor calls - this is where sync methods become async (requiring await), and the ActorSendable sorts of checks have to be performed. Would it be reasonable to just forbid passing anything inout across these actor boundaries?

This fixes the unnecessary limitation of intra-actor references, and such a limitation could be relaxed in the future if there is a safe model for it. It would also eliminate a complicated part of the actor model we'd otherwise have to nail down.

-Chris