[Actors] Revisiting "nonisolated let" with more implementation, usage, and teaching experience

So, we have been thinking about distributed actors and have a pretty solid idea of a workable model (with a pull request that implements them). I'll lean on that for my answers.

It can be part of the handle, yes. However, in the distributed case, that might not be desirable, because creating a remote proxy for an actor then requires ping-ponging with the machine that has the real actor, so you can replicate the extra information.

Whatever state makes up the identity has to be immutable and replicated, yes. In an indirect or distributed actor case, it's something more than the address of the local object. In the pull request I referenced earlier, identity is the (network) address of the actor + the transport used to talk to it.

I don't understand this last bit about nonisolated being misleading. If something is part of the identity, you're going to need to be able to access it synchronously (hence, nonisolated) and for the distributed case, you also need it to be replicated so it's available on a remote proxy for the actor.

We're getting a bit far afield of nonisolated let, so it's probably best to go to another thread to dig further into distributed (or indirect) actors. We were planning on starting a discussion of distributed actors in a couple of weeks, once more of the non-distributed actors dust settles.

Hmm. Whether isolated is handled as a value-directed notion or a type-directed one should be orthogonal to nonisolated. Either way, a nonisolated method in an actor will alter some aspect of its self parameter, making it either non-isolated (in the value-directed design) or making it @async (in the type-directed design).

Your description of the semantics of the type-directed approach is correct. However, your second displayAccount is not equivalent to the example I used. The type-directed equivalent to the example I used is:

func displayAccount(account: @async BankAccount) {
 print("Account #\(account.accountNumber) owned by \(account.owners.joined(separator: ", "))")
}

The value-directed equivalent to your @sync version is this:

func displayAccount(account: isolated BankAccount) {
 // Same synchronous accessing to BackAccount actors
}

There are certainly differences between the type-directed and value-directed approaches, and we should continue to discuss those over in the review of SE-0313, but they should not have any impact on nonisolated.

Based on the above, I think you're misunderstanding the differences between the approaches. There are definitely differences to discuss, but both approaches can model what you're discussing quite directly.

We haven't seriously considered it, no. Outside of nonisolated let, use of nonisolated in actors is actually quite rare. That's part of the reason I'm making this correct proposal, because (if you put nonisolated let aside) you can make great use of actors without having to learn about nonisolated for quite a while. If we switch the polarity like you mention, there will be a lot of isolated and relatively few things in an actor that aren't labeled as isolated.

Doug

2 Likes