I read earlier versions of the Actor proposal, and maybe I misunderstood, but it seemed like the design was oriented towards UIKit. That’s what made it interesting for me. Has that changed?
Specifically, actors would alleviate the the mental overhead of constant dispatch queue management littering iOS codebases. Certain UIKit classes would gain @UIActor and suddenly you get a compiler error if you try to modify a view from a background thread. I can’t seem to find any references to that in the current proposal.
Regardless, I’m excited for actors to land in the next release. I’m just concerned adoption will be similar to Swift 3’s do/try/catch syntax, which didn’t take off until UIKit converted all fallible synchronous methods from `(Data?, Error?)` to `throws`.
As far as I know, the new concurrency features can be adopted gradually which would make it very simple for developers to transition from the current completionHandler-based model to the new async/await-based model. Every Obj-C UIKit method with such a completionHandler parameter would from now on be available in two ways from Swift:
1. as usual, with completionHandler
2. new, without completionHandler, marked as ‚async‘ and returning the input types of the completionHandler
No, interacting with UIKit is just one example usage, though important enough to warrant special constructs like that. The people that seem most excited to me are those that work with server side Swift.
From the server side perspective, this Actor implementation is cheap(to develop), safe and more developer friendly.
But i don't know if it will be the most performant implementation as it will depends of how much state copy between threads its involved (as this is the common bottleneck in performance on a multi-threaded implementation).
So a more classic implementation might perform a little better, but i don't know if this will also stand true in Swift as the compiler might use tricks behind the curtains to optimize things giving the people behind this also control the Swift compiler.
I'm also intrigued where the Actor model will leave Combine. Are they designed to work together?
Many of the Rx based architectures (The Composable Architecture in Swift, React, Cycle.js, etc) that have appeared – all inspired by Elm (itself inspired by Erlang/OTP?) – seem to lean on a kind of pseudo actor model where messages are passed into a kind of 'actor', its state is modified, side-effects are initiated and performed asynchronously, and subscribers are updated in turn.
With the Rx based architectures at least this created a lot of boiler plate and the need to create a separate enum just to pass messages into the monad with a big switch statement to route them all.
Now, if I understand correctly, this actor model would facilitate a very similar workflow but without an additional dependency and far less boilerplate.
Instead of passing messages into the 'actor' via a messages stream – you can just call methods on the actor. Then, an actor can manage a 'state' property internally and simply forward changes to that state to via a publisher (PassthroughSubject/BehaviorSubject).
With regards to Elm and some others, you have Functional reactive programming, reactive programming, Rx, it goes by a variety of names. It’s most famous for transforming UI development some 8? 10? years ago with the widespread adoption of React. But it’s been around longer in various forms. Implementations can widely vary but the general concepts are very similar.
One of those frameworks you mentioned is React, so that’s not quite true. Elm is cited in things like Redux, but React was first deployed on the Facebook website a year or more before Elm was even first released. And FRP has been around much longer.
I'm also wondering whether SwiftNIO will be rewritten to use actors, or it will stay "old-school" for the sake of efficiency. Very much looking forward to Swift maturing for backend development either way.
It's an amazing, rich language with the only drawback of the compiler being shamefully slow (though it's probably not that bad on Linux, where there are no legacy ObjC frameworks). Other than that, I love the idea of having an ARC-based modern type-safe language on the backend, possibly with the new concurrency model being at the core of the network framework.
I've followed the conversations around actors, and i'm really curious to see what the end-result will look like, considering the actor model seems to have been designed independantly from the execution infrastructure. In particular, the concepts of mailbox, executor, etc don't seem to be very apparent so far.
By contrast, i see a lot of talk about actor "isolation", inheritance, reentrancy, etc... Which i don't see mentionned often in erlang / OTP style actor systems...
I'm really excited to see what is essentially a mainstream language trying out actors - whatever they end up with, I expect there will be a lot to learn from.
> The answer is: “it depends”. It depends how your or others' code uses Person. If two pieces of code, running concurrently, update Person.name at the same time - your app will crash
Damn, I honestly forget what it's like to program with threads in languages that let this happen.
Why does the author keep saying that the original Person definition can crash the app? That's not true, is it? You'll just get races, as far as I know.
If that's the case, it's not clear to me that it shouldn't crash the app (versus the alternative of likely corrupting data) in release builds. I guess this is similar to the "assertions should/should not be turned on in release builds" debate, which IMO has good points on both sides.
But maybe there's an extra complicating factor of TSan causing significant performance penalties making it impractical for it to be on in release builds?
Don't get me wrong- I agree with the sentiment that crashes are better than corruption. But, as someone else already mentioned, the thread sanitizer does cause significant overhead from all of the debug info it holds (maybe a release version could just be performance tuned). But, also, Swift already has asserts that go away in release builds, as you mentioned. So it's at least consistent.
So given this example where actor methods are magically syncronous within the actor and async outside of the actor, did Swift solve the whole red/blue functions pain? Or at least seriously alleviate it.
It uses async/await so they are still coloured functions - which, while coloured, doesn’t make it more painful to call than Non-concurrent methods I guess
It seems more like syntax sugar to easily await synchronous methods on the actor specific task scheduler with a lot of linting thrown in to help you get it right.
In C# you might have to use the following and worry about the private member access yourself.
Looking at the Person class in the article, which has just a “name” property with String type…
I think if you mutate that string from multiple threads — like by appending to it — you would get crashes pretty easily.
I’m really not sure if you would see crashes if you simply access and assign to the name property (rather than mutating the value it is pointing to). I have not seen guarantees on this. Maybe I missed it, but if not, even if it appears to work today, it may not tomorrow.
Yes, it does crash if two threads write to a property at the same time. The worst thing about this kind of bug is the inconsistency - often being discovered first by real users. There are also a plethora of shared state bugs that should be reduced with clearer concurrency semantics. All-around big step forward towards Swift's goal of being a "safe" language.
For example, how could Swift Actors implement the following:
TrainController ≡
moving := False // train is initially not moving
isOpen := False // door is initially closed
open ↦ moving ?? // Received request to open door, there are two cases for moving:
False ↠ // Case moving=False, then
isOpen := True; // then set isOpen to True and then
DoorController.open // send door an open request in hole of the region
True ↠ Throw TrainMoving[] // Case moving=True, then throw TrainMoving
close ↦ Hole DoorController.close ; // Received request to close door, so send door a close request
// in a hole of the region and after door reports that it is closed,
isOpen := False // set isOpen to False
move ↦ isOpen ?? // Received request to move train, there are two cases for isOpen:
False ↠ // Case isOpen=False, then
moving := True; // set moving to True and then
EngineController.move // send engine a move request in a hole of the region
True ↠ Throw DoorOpen[ ] // Case isOpen=True, then throw DoorOpen
stop ↦ Hole EngineController.stop ; // Received request to stop train, so send engine a stop
// request in a hole of the region and after engine reports that it is stopped,
moving := False // set moving to False
36 comments
[ 3.4 ms ] story [ 78.6 ms ] threadSpecifically, actors would alleviate the the mental overhead of constant dispatch queue management littering iOS codebases. Certain UIKit classes would gain @UIActor and suddenly you get a compiler error if you try to modify a view from a background thread. I can’t seem to find any references to that in the current proposal.
Regardless, I’m excited for actors to land in the next release. I’m just concerned adoption will be similar to Swift 3’s do/try/catch syntax, which didn’t take off until UIKit converted all fallible synchronous methods from `(Data?, Error?)` to `throws`.
But i don't know if it will be the most performant implementation as it will depends of how much state copy between threads its involved (as this is the common bottleneck in performance on a multi-threaded implementation).
So a more classic implementation might perform a little better, but i don't know if this will also stand true in Swift as the compiler might use tricks behind the curtains to optimize things giving the people behind this also control the Swift compiler.
Many of the Rx based architectures (The Composable Architecture in Swift, React, Cycle.js, etc) that have appeared – all inspired by Elm (itself inspired by Erlang/OTP?) – seem to lean on a kind of pseudo actor model where messages are passed into a kind of 'actor', its state is modified, side-effects are initiated and performed asynchronously, and subscribers are updated in turn.
With the Rx based architectures at least this created a lot of boiler plate and the need to create a separate enum just to pass messages into the monad with a big switch statement to route them all.
Now, if I understand correctly, this actor model would facilitate a very similar workflow but without an additional dependency and far less boilerplate.
Instead of passing messages into the 'actor' via a messages stream – you can just call methods on the actor. Then, an actor can manage a 'state' property internally and simply forward changes to that state to via a publisher (PassthroughSubject/BehaviorSubject).
That would be pretty nice!
No, Elm is just another implementation, not the invention.
https://en.wikipedia.org/wiki/Actor_model
See the following for Actors:
https://papers.ssrn.com/abstract=3418003
Actors are something different.
Not really. You didn't mention Redux and you explicitly mentioned React, hence my clarification.
It's an amazing, rich language with the only drawback of the compiler being shamefully slow (though it's probably not that bad on Linux, where there are no legacy ObjC frameworks). Other than that, I love the idea of having an ARC-based modern type-safe language on the backend, possibly with the new concurrency model being at the core of the network framework.
By contrast, i see a lot of talk about actor "isolation", inheritance, reentrancy, etc... Which i don't see mentionned often in erlang / OTP style actor systems...
> The answer is: “it depends”. It depends how your or others' code uses Person. If two pieces of code, running concurrently, update Person.name at the same time - your app will crash
Damn, I honestly forget what it's like to program with threads in languages that let this happen.
But maybe there's an extra complicating factor of TSan causing significant performance penalties making it impractical for it to be on in release builds?
In C# you might have to use the following and worry about the private member access yourself.
I think if you mutate that string from multiple threads — like by appending to it — you would get crashes pretty easily.
I’m really not sure if you would see crashes if you simply access and assign to the name property (rather than mutating the value it is pointing to). I have not seen guarantees on this. Maybe I missed it, but if not, even if it appears to work today, it may not tomorrow.
"One Actor is no Actor."
The fact that "there are no variable races in an Actor" is a side-effect of Actor concurrency.
For example, how could Swift Actors implement the following: