[Pitch #4] Actors

Splitting this out, I think there is a very big issue here that is not coming through clearly in my feedback. I strongly believe that nonisolated should be split out to a follow on proposal, but I am /not/ arguing that we drop it from the model. This is exactly how we're handling global actors - split out to a follow-on proposal - even though they are also critical to the model.

Through the evolution of the actors proposal, we've progressively pared back the functionality ascribed to actors, generalizing that functionality and making it orthogonal to actors. This has made actors and structured concurrency more of peers that share the same implementation details (e.g. Sendable).

What are the fundamental nature of actors?

An Actor is a nominal type that collects a bag of state together and allows one to define methods on it, providing isolation through async messaging of its mailbox. This is a simple and beautiful idea!

By analogy, the non-concurrent part of swift has closures and structs/classes. Closures allow one to capture state and provide a single operation against that state. A struct allows you to explicitly declare the state you want to represent, and define multiple operations against it. This is what I meant in the intro rewrite when I said actors are a "state first" design like structs/classes when compared to closures.

Nominal types are great, because they allow a bunch of cool things that closures cannot do: e.g. they can conform to protocols, allow POP abstractions built with them, are the key for resilience, and support for multiple methods that interact with that state.

@sendable closures in structured concurrency and actors provide the same duality for the concurrent world!

The problem with the presentation of the proposal

Getting to my problem, the proposal does not express this simple nature! Where actors should be a simple nominal type with isolated self and the sync/async promotion dance going on, instead the proposal spends most of its words talking about complexity related to nonisolated, which isn't general and isn't the fundamental nature of actors. nonisolated is all about /breaking/ the fundamental property that actors provide - isolation of data.

To reiterate, I agree with you that nonisolated may be an important part of the pragmatic eventual user model, but it is an additive feature, and the presence of all the nonisolated complexity in this proposal is distracting and makes it very difficult to evaluate and reason about the actual actor part of the proposal.

The basic actors proposal (ignoring the nonisolated stuff) is not good enough

Furthermore, the proposed protocol model has a significant number of problems that will cause excessive use of async, does not allow protocol abstraction across actor definitions, doesn't interact well with generics, and has other problems I laid out in the motivation of the whitepaper I wrote. While the introduction of 'nonisolated' parameters is a positive step, there are still major holes in the proposal.

At the end of the day, I hear you state vociferously that things are "non-negotiable" but the model you're proposing is missing basic abstraction facilities that all other nominal types support. I can't see how introduction of actors without these basic features would be considered acceptable.

In short, while it isn't "necessary" to split all the non-isolated complexity out of the proposal, doing so would make it much easier to evaluate the core of actors, land it cleanly, then build on top of it. "non-isolated" members are not an acceptable substitute for proper interaction with the protocol and generics system in Swift.

-Chris

6 Likes