Hacker News new | ask | show | jobs
by kjaleshire 1778 days ago
Swift actors seem to differentiate from other actor implementations (see Erlang) which have a decoupled message queue. Calling into a Swift actor may be non-blocking, but the result must still be await'd and from the actor's perspective all calls are sequential and synchronous.

By this token, actors seem to be the language-level implementation of a class where all methods are asynchronous, and also being protected by the same lock.

The novel feature seems to be cooperative scheduling amongst actors.

3 comments

I spent a bit of time watching the sessions after this years WWDC. I’m primarily an Elixir developer but have wanted to try Swift for a while, so the introduction of Actors felt like a good point to jump in.

My enduring impression after learning Swift Actors is that a LOT of additional complexity is introduced because of reference types. The data inside an Elixir process is just that: data, but the possibility of the data in a Swift Actor being a reference to a class suddenly makes everything complicated.

Regardless of the technical achievement from a compiler perspective I found that Swift’s Actors didn’t map well to my understanding of them from Elixir/Erlang and that they weren’t a net positive for solving the kinds of problems actors are suited for. I’ll concede this is all very personal and subjective though.

My understanding is the primary role of Swift actors is to support safe global state in an async environment.

I plan to use actors enums for states in my next major app version release.

Or at least I was, until Apple decided to backdoor the iPhone in the absurd notion that it protects kids. Now I’m trying to figure out how to migrate off their platform entirely.

They seem to have done a great job of combining async with multithreading by using the actor pattern which is really smart.

They also seem to have an m-to-n scheduler (not sure if in user space or kernel), so you can have more actors than “threads”.

After having tried to follow the discussions on swift forums on concurrency and actors, i still couldn't make my mind on whether their design was "fancy" smart (aka : something subtle and brilliant, that few developpers will get their grasp on and lead to inscrutable concurrency bugs), or "stupid" smart (aka : take a complex problem and make it look simple).

Actors in systems like erlang seem to make concurrency simple, and the model seems to be easy to grasp.

On the contrary, a few code samples i've seen on swift forums made my mind twist trying to understand how the code was going to be executed..

The big difference AFAIK with Erlang (other than reference types) is that Swift's model is reentrant, while Erlang's is not.

This is why `await` is such an important keywords to litter around your code - anything can happen in between when you await and when you come back, including actor message processing. You could have another invocation against your actor instance happen in tandem.

This definitely increases the learning curve, but likely still saves time later when you are fighting various deadlock conditions.

that's exactly the part where i lost it. The code samples talking about reentrancy and its various quircks in some proposal discussions really made me wonder where the whole thing was going..

its seems to me having an async public interface with a sync internal implementation is the most straightforward architectural design for actors, but obviously they thought it was too limiting. Do you have any idea why ?

If an actor system is fully synchronous, it is much less efficient and can't be reentrant.

Actor implementations tend to be split on reentrancy. Having multiple paused in-flight invocations of the actor means that you need to have clearly understood suspension points (hence await keywords). Non-reentrant actors like in Erlang can deadlock if two actor instances are calling one another. Because of the deadlock and some inefficiency concerns, some actor systems allow you to decide reentrancy per-actor as well.

Because Swift concurrency is an upgrade on top of decades-old systems, I believe a certain amount of additional complexity was required whether it was built as reentrant or not.

It was a bit harder to find than I expected, but here is a discussion piece around the initial choice of reentrancy by default. https://github.com/ktoso/swift-evolution/commit/d55bbbd6cc1a...

Erlang does not implement the Actor model. The similarity is accidental.