I'd like to understand why we should be confident that this step results in a usable programming model.
While reentrant actors still technically eliminate data races, they create a very racy programming experience, akin to sharing a bunch of atomic properties across multiple threads. True, it's slightly different, because your thread of execution can only be interrupted where it issues an await
instead of at arbitrary points, but if the actor's properties have any important relationships, before any await
you have to be sure invariants are intact, and you have to be prepared for the actor's mutable properties to have “shifted underneath you” when the await is over. We use locks to avoid both of these effects in multithreaded code, and it seems the same basic kind of care is needed here.
IIUC part of the reason async/await has been so successful in other languages is that it lets us reason about async code using the same tools that apply to synchronous code, but reentrancy seems to substantially break that illusion. Common idioms, like using the properties of an instance to hold the state of a single larger computation, will break most spectacularly and with exactly the same kinds of unpredictability as if there were an actual data race, if deployed in the usual ways in reentrant actors.
I have yet to read through all the documents (a quick scan finds no mentions of reentrancy), so apologies if I've missed it, but it seems to me we at least need a set of “reentrant actor programming guidelines” if we're going to adopt this model. Does that exist somewhere?