- What is your evaluation of the proposal?
+0.5
Managed thread-safety will be a huge benefit to Swift and its users, but I find even this model, reduced though it may be from earlier pitches, to be more limited than it seems to need to be.
As an aside, the proposal could do with a summary of the proposed solution before diving into definitions interspersed with examples. Even knowing what actors are does not prepare you for the specifics of Swift's implementation.
Positives
Compiler Checked: Obviously the biggest benefit of this proposal is the compiler checked thread-safety. This will be a huge benefit to the community, not only in the safety itself, but in performance, as it will replace manual DispatchQueue
usage and even locks in many cases.
Discoverability and Teachability: Adherence to Swift's existing class model will ease developers into actors and provides a clear evolutionary path for classes which may eventually need thread-safety. This allows developers to reuse existing knowledge and skills in building these types. This adherence also makes the feature much easier to teach, as you can start with classes, illustrate the issues around thread-safety, and evolve to an actor. You can even illustrate the functionality of an actor within a class before moving on to the real thing. This should make actors much easier to adopt, accelerating usage across the ecosystem. Keeping class capabilities also provides a more complete set of functionality, especially inherited state, that is important for many actor use cases.
A Model We Know: In many ways, the actor model presented in the proposal works like the DispatchQueue
safety model used in Swift and Objective-C already. Given this fact, users should be able to transition their mental model to actors rather quickly, delta the particulars of actors. (In fact, I preferred the use of "queue" rather than "mailbox" to describe the actor's internals for this reason. Rather than confusing I found it a familiar way to describe the actors' main safety mechanism. And since Swift actors are not addressable, I don't believe the "mailbox" metaphor works well and is less accurate anyway. In fact, it seems likely the community will eagerly adopt the "queue" metaphor in blog posts and social media, so the proposal may as well go along.)
Negatives
Async by Default: In following the various pitches and this proposal, I've never seen a complete explanation for why this model starts with async only access to even read-only state, aside from an implicit "that's how actors work". Take this mention from the proposal:
Even non-mutating access is problematic, because the person's name
could be modified from within the actor at the same time as the original call is trying to access it.
This is clearly the case, but the proposal makes no mention as to why we can't employ the obvious solution to this problem, a lock, to provide synchronous access. Historically, actors were created to eliminate the need for the locks (and to supported more distributed systems), but the 50 years of hardware advancement since then have made locks nearly free. It seems like this would be especially true when the concurrency system is being provided by the language itself. Of course, this may just be a limitation of the current proposal; I haven't kept up on the isolation features since they were removed (and they were very hard to understand). In fact, in one of the early pitch threads it was suggested that manual locking could be a solution to the synchrony problem, I'd just have to provide it myself. If that's the case I don't see why Swift couldn't do it for me since that would be faster and less buggy anyway.
Being able to offer safe, synchronous APIs is an important feature. Like I mentioned above, if actors work like types already familiar to Swift developers, it makes the feature far more approachable. It's far more discoverable if users don't have to radically change the way they use actors. It's far more teachable if it leaves as much of the existing Swift programming experience alone. Finally, synchronous APIs are important to the overall API design experience of Swift. We can see an example of this design impact in the proposal.
func primaryOwner() -> Person? { return owners.first }
Now, in typical Swift this would obviously be expressed as a computed property.
var primaryOwner: Person? { owners.first }
However, due to the actor's async access requirement, it can't be, if we want to offer this value publicly. Of course, if we gain property effects, this issue is somewhat mitigated, but it would still require an apparently unnecessary use of async
. I say "apparently" because unless the user understands why actors require async
access, they won't understand the necessity. And this proposal hasn't offered a justification for it either, other than an implicit "that's how actors work". (Which seems like a circular justification to me.)
Any change to how we fundamentally write Swift has a high justification cost. I don't believe this proposal has justified that cost.
Only Kinda Actors: I think this proposal should more thoroughly describe the Swift version of an actor how it differs from actors in other languages, as well as from the general definition. As far as I can tell they're rather different in that Swift's actors aren't parallel by default, aren't distributed, don't send messages, aren't addressable, and don't operate solely on other actors.
- Is the problem being addressed significant enough to warrant a change to Swift?
Yes! I manually implemented essentially what's described here in Alamofire 5 using shared serial DispatchQueue
s and locks. It wasn't easy, and even with the thread sanitizer, probably isn't completely safe. Being able to replace it all with a model built into the language will be great, even if it does mean another rewrite.
- Does this proposal fit well with the feel and direction of Swift?
In many ways, yes, but falls short, especially in the shape of APIs you can create with it. As I wrote above, I don't believe the proposal has gone far enough to justify the radical shift in API design that would be required for Swift developers to adopt the suggested model.
- If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
N/A
- How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
Somewhat in depth from the Swift side of things. I've attempted to keep up on all the pitches, participated in the threads, and have implemented some actors using the various snapshots.