[HN Gopher] Swift Evolution: Actors
       ___________________________________________________________________
        
       Swift Evolution: Actors
        
       Author : mpweiher
       Score  : 163 points
       Date   : 2021-03-16 18:33 UTC (4 hours ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | javajosh wrote:
       | I find it hard to accept that a real actor model can be
       | implemented at compile time!
        
       | layoutIfNeeded wrote:
       | Another thing that's about to be bolted onto Swift at the
       | language level (instead of making it a library). Sad!
        
       | xiaodai wrote:
       | Will it go the way of AD in Swift or Tensorflow for Swift. Maybe
       | not coanit might fit in the Swift ecosystem
        
         | danappelxx wrote:
         | From what I can tell UIKit and friends will adopt this actors
         | eventually via bridging (just like they adopted Swift 3's error
         | handling).
        
       | williesleg wrote:
       | I'm going to archive this thread and sell it as an NFT
        
       | the_duke wrote:
       | I love actors, but baking them into the language like this seems
       | like the wrong approach to me.
       | 
       | The language should provide all the necessary abstractions to
       | create an isolated context. Actors can then "just" be a default
       | abstraction provided by the standard library.
       | 
       | Side note: has the Swift cross platform support improved? I was
       | very much looking forward to using Swift as a general purpose
       | language, but Apple didn't seem very interested in making it a
       | true first class cross platform language. I believe IBM also
       | dropped their "Swift for the server" efforts a while ago due to
       | similar concerns.
        
         | Someone wrote:
         | _"has the Swift cross platform support improved?"_
         | 
         | That's hard to answer without a "since when", but the answer
         | probably is "yes". See https://swift.org/platform-support.
         | There are Windows binaries now, for example.
         | 
         | Many of Apple's libraries aren't available on non-Apple
         | platforms, though, so many would say it hasn't improved enough
         | to be competitive with other languages.
        
         | drmidnight wrote:
         | While it takes some work I have successfully run Swift code on
         | the usual suspects (iOS/Mac) as well as Windows, Android and
         | Linux.
         | 
         | If you ditch Foundation and rely on C libs you are able to use
         | it pretty much anywhere.
        
           | anonymouse008 wrote:
           | What are you using for GUI libraries? Or are these mostly
           | accessed from the command line?
           | 
           | In my own experimentation, I've seen some success with Vapor
           | 4 and PlotHTML
        
             | drmidnight wrote:
             | I've actually been developing my own UI library backed by
             | SDL. It currently uses a DSL-like system similar to
             | SwiftUI. I just spent some late nights working on a "hot-
             | reloading" system, though it only works on Mac/Linux
             | currently.
             | 
             | In theory any C based UI libs that support those platforms
             | should work as long as they can be called from Swift.
        
               | anonymouse008 wrote:
               | That's pretty dang cool! I'd love to contribute, if
               | you're open to it.
               | 
               | The most difficult thing I've done with Swift/C was
               | packaging a Python interpreter inside a Mac app with a
               | few lxml dependencies called with PythonKit. Might not
               | begin to scratch the surface of what you need though...
        
             | DaiPlusPlus wrote:
             | > What are you using for GUI libraries? Or are these mostly
             | accessed from the command line?
             | 
             | I'm not a Swift user, but the approach I've seen is people
             | using it to run a localhost HTTP server for a HTML+JS
             | frontend.
        
           | bsaul wrote:
           | i'd be EXTREMELY interested in knowing more about that. I'm
           | currently developing an app on iOS in swift, in the hope of
           | porting the model layer to other platforms such as android (i
           | don't mind redevelopping the UI).
           | 
           | i have been carefully avoiding any objective-c code so far,
           | but i must admit i haven't been to careful with foundation
           | dependencies.
           | 
           | Do you have a blog post explaining what you did and what
           | limitations you encountered ?
        
         | EdwinLarkin wrote:
         | Yeah.I would say the Swift ecosystem is too detached from
         | different platforms than iOS/macOS.
         | 
         | It's a nice language but useless if you want to use it as a
         | generic purpose tool.
        
           | wealthyyy wrote:
           | Jony Ive - Introducing Swift Actors .......
        
         | machineko wrote:
         | Its okish on ubuntu and wsl but windows still lag hard. Worst
         | think is very narrowed libaries working only on apple devices
         | even most cool open source projects are just locked and are
         | looking only on apple ecosystem (dont get me wrong its huge
         | enough to just ignore other ecosystem at the moment sadly)
        
         | eternalban wrote:
         | > The language should provide all the necessary abstractions to
         | create an isolated context. Actors can then "just" be a default
         | abstraction provided by the standard library.
         | 
         | A stated goal is static, compile time, prevention of
         | concurrency error. You can't do that with a concurrency library
         | unless you restrict yourself to purely deterministic code.
        
         | staplung wrote:
         | The "official" Swift LSP was begun in 2018 but there doesn't
         | seem to be much going on there these days. The readme still
         | says "SourceKit-LSP is still in early development, so you may
         | run into rough edges with any of the features." That hasn't
         | changed since the first commit. I can't help but feel that part
         | of the problem is that the language is too complicated.
        
           | liuliu wrote:
           | sourcekit-lsp is actually pretty light-weight implementation
           | as it shares the same sourcekit code with Xcode. VSCode's
           | sourcekit-lsp integration is OK to me.
           | 
           | The only issue for me is that I don't use Swift Package
           | Manager, hence, the build system (Bazel) integration is
           | simply not there (the BSP support from sourcekit-lsp is
           | dead).
        
         | favorited wrote:
         | I have some personal Swift-on-the-server projects deployed in
         | "production" (as in, I use them every day, but I'm the only
         | user) and it works great for me. They're running in Docker
         | containers deployed to Heroku; there might be better ways to
         | deploy it, but I'm not a backend engineer anymore so this is as
         | much as I knew how to do.
         | 
         | I haven't tried it on Windows yet, but I know that it is
         | officially supported now.
        
         | rozap wrote:
         | but..the "provide all the necessary abstractions to create an
         | isolated context" is the hard part. It trickles into every part
         | of execution. How do you do isolated contexts without saying
         | any process can be preempted at any moment? How do you isolate
         | things when there's shared memory? To do this right you end up
         | with something like Erlang which makes a lot of sacrifices in
         | order to get there, though you have a fighting chance at
         | dealing with concurrency. And if you bolt it on to the runtime
         | without those pieces in place you end up with something like
         | Akka which has tons of gotchas and ends up being way more
         | confusing than just programming the way the JVM wants you to.
         | 
         | it seems like these fundamentals are in tension, and tradeoffs
         | need to be made, which just means that there won't be a one
         | size fits all paradigm. maybe someone will create something
         | that is truly magic and does everything, but more likely
         | they're trying to sell you something.
        
           | slavapestov wrote:
           | There are also the various static checks that prevent you
           | from accessing actor-isolated state outside the actor, or
           | passing non-Sendable state across actor boundaries. It's not
           | clear how a general language extension mechanism could
           | implement those.
        
       | layoutIfNeeded wrote:
       | This is not gonna end well:
       | https://tclementdev.com/posts/what_went_wrong_with_the_libdi...
        
         | bsaul wrote:
         | No idea why you got downvoted. The fact that the first
         | implementation of the actor system is most certainly going to
         | be on top of libdispatch makes it a very interesting property.
         | Libdispatch is really not known for being able to spawn
         | thousands of "light thread". And so there is indeed a potential
         | pitfall in making asynchronous + concurrent code easier.
         | 
         | However, after having read a lot of the swift proposal relative
         | to concurrency, i am still unsure if the end result of
         | production code is going to be lots of actors running in
         | parallel, or just lots of async calls multiplexed on a few OS
         | threads.
        
       | alexashka wrote:
       | This seems to be a way to tackle concurrency, without addressing
       | distributed programming.
       | 
       | Why?
       | 
       | As far as I can tell, both Erlang and Akka (the two cited
       | examples that implement actors) do both concurrent _and_
       | distributed systems.
        
         | bsaul wrote:
         | That was my first reaction as well when i saw the way swift
         | team was laying out the roadmap to actors. The broke all what
         | we consider an "actor system" into pieces, and implemented
         | every part in different, hopefully orthogonal, proposals..
         | 
         | If that works it's going to be quite interesting. But i feel
         | that it goes against what i've learned from go language design
         | decisions : concurrency is such a deep concern that you have to
         | build the whole language around it, as well as from erlang,
         | where they basically designed the virtual machine around the
         | actor requirements.
         | 
         | It's going to be some interesting times..
        
         | ex3ndr wrote:
         | Because distributed part is library not language feature?
        
           | pjmlp wrote:
           | Erlang, Axum, Agent Tcl, Active Oberon are just a few
           | examples where it is a language feature.
        
           | fearthetelomere wrote:
           | Actors aren't just about local concurrency, and if a language
           | is attempting to bake them in, they should leave some room
           | for the distributed case in my opinion.
           | 
           | One of the biggest benefits of using actors is that whether
           | an actor exists on the same machine or across the network can
           | be abstracted away from you. You're just sending messages, so
           | you can send a message over the wire and it would be as
           | simple to the developer as sending it locally. Not
           | considering this use case would make it a very limiting
           | language feature.
        
           | alexashka wrote:
           | Have they tried and found this to be the optimal case? If so,
           | those findings should be part of the proposal if it were up
           | to me.
           | 
           | Distributed programming is not a little add-on you can slap
           | on top of a non-distributed system if history has taught us
           | anything.
        
       | blt wrote:
       | The idea of the "mailbox" reminds me of Dispatcher.BeginInvoke in
       | C# on Windows. It is very powerful, but can also lead to messy
       | code where many threads are mutating shared state and failing to
       | fully reason about all the other mutations that can happen.
       | 
       | Systems with explicit communication, i.e. based on queues,
       | encourage the programmer to limit the number of possible ways in
       | which worker threads can interact with the thread that manages
       | mutable state. They also require something like a big switch
       | statement where all possible interactions are listed in one
       | place. It seems like in actor-based code, all the possible
       | interactions with the mutable state could be spread across the
       | code base.
       | 
       | On the other hand, these hand-written message loops and switch
       | statements are essentially the same code that the compiler would
       | generate for an actor's mailbox processing loop. One could argue
       | that writing them by hand is a waste of effort. Programmers
       | simply need to use discipline. (Similar to virtual dispatch in
       | C++, for example.)
       | 
       | I am curious about the opinions of programmers more familiar with
       | concurrent architectures. Does the actor model make it easy to
       | write concurrent spaghetti code?
        
         | fearthetelomere wrote:
         | >Does the actor model make it easy to write concurrent
         | spaghetti code?
         | 
         | I think you could write concurrent spaghetti code in any
         | environment just as easily, to be honest. I also think it
         | really depends on which actor-model implementation you're
         | using. Each offers their own unique experience, as I've found
         | that there's a noticeable difference in the Scala+Akka approach
         | vs Elixir+OTP, for example.
         | 
         | The actor model is just one way of reasoning about concurrency.
         | Your mailbox serializes/linearizes your interactions so you
         | don't necessarily need locks. Because you get that for free,
         | you can write "single-threaded" code to handle each message.
         | Messages can be sent across a network, so now you can
         | concurrently interact with remote actors too. The simplicity of
         | the model stops there.
         | 
         | Concurrent code gets complicated very quickly by nature. If you
         | architect your application to have messages causing ripple
         | effects in your system, your application behavior is going to
         | be very difficult to reason about. But that's nothing new,
         | either. Instead of sending messages, concurrent function calls
         | could produce the same issue.
         | 
         | Is reasoning about message flows and behaviors hard? Yes, but
         | that's just a byproduct of concurrency. Like you said,
         | "programmers simply need to use discipline", but everyone will
         | disagree on what discipline looks like. Each actor model
         | implementation will have their "best practices" to mitigate the
         | complexity of concurrent interactions, as will each
         | organization using said implementation for their project. At my
         | work, the way we use Scala+Akka was very structured and not at
         | all the way I expected, having been used to Elixir+OTP.
         | 
         | As I think the issues of the actor model are actually issues
         | with reasoning about concurrency in general, I would pick
         | actors over coroutines just for the up-front structure and
         | simplicity it provides.
        
       | pixel_tracing wrote:
       | I really don't like that we have the overhead of a new keyword
       | called actor
        
       | mrkeen wrote:
       | > we can implement a correct version of transfer(amount:to:)
       | // Safe: this operation is the only one that has access to the
       | actor's isolated         // state right now, and there have not
       | been any suspension points between         // the place where we
       | checked for sufficient funds and here.         balance = balance
       | - amount                  // Safe: the deposit operation is
       | placed in the `other` actor's mailbox; when         // that actor
       | retrieves the operation from its mailbox to execute it, the
       | // other account's balance will get updated.         await
       | other.deposit(amount: amount)
       | 
       | Am I correct in thinking that the system temporarily destroys
       | money here (and hopes to recreate it if the receiver doesn't
       | crash?)
       | 
       | If I have a closed system of actors constantly transferring money
       | among themselves, and I poll to see the total amount of money in
       | the system, will it fluctuate?
        
         | rkalla wrote:
         | In the code above it certainly looks like that - is this not
         | idiomatic swift-finance code though?
        
         | msoad wrote:
         | There is also Swift Atomics[1] that is probably needed here
         | 
         | [1] https://swift.org/blog/swift-atomics/
        
         | ogre_codes wrote:
         | I was thinking the same thing as I read this. Keep in mind,
         | these examples are meant to illustrate how Actors work, not how
         | to write good banking code.
        
         | centimeter wrote:
         | This is an especially poor choice of example given that it's
         | the canonical example for STM, and STM _actually_ solves the
         | problem.
        
         | syrrim wrote:
         | They say that the `deposit` call is placed in `other`s mailbox.
         | As long as the mailbox is preserved between restarts, then
         | there is no danger of the money disappearing. The money will
         | temporarily be unavailable - that is, in neither account's
         | balance. But the money is still _somewhere_ , in the mailbox.
        
           | gpderetta wrote:
           | A crash between updating balance and putting the message in
           | the mailbox can still result in an inconsistent state.
        
         | liuliu wrote:
         | I think that you are correct. There is a paragraph on actor's
         | reentrancy: https://github.com/apple/swift-
         | evolution/blob/main/proposals... which points out that you can
         | definitely get balance before await, therefore, have fluctuated
         | total.
        
       | Nican wrote:
       | Oh! Actors is one of my favorite paradigms of lately. I have been
       | reading plenty about Akka as well.
       | 
       | When I start looking into the subject further, I start falling
       | into a rabbit hole of how Actors are sometimes treated as a
       | database, that is hard to query, and provides no transaction-
       | ability across actors. There is some argument that Actors could
       | be reimplemented using Postgres' "SELECT ... FOR UPDATE", since
       | you can lock the row for the duration of the transaction.
       | 
       | Anyone else have experience managing large amounts of data inside
       | of Actors have a say about this?
        
         | halfmatthalfcat wrote:
         | I use Akka extensively and have not heard (and would never) use
         | Actors in that capacity.
        
         | dmux wrote:
         | You have to walk a fine line with Akka IMHO. Having inherited
         | and supported an Akka Cluster for 4+ years, I'd strongly
         | recommend that you evaluate whether you really need an Actor
         | based system or if a plain-old set of services talking to each
         | other via a message-broker would suffice.
         | 
         | The particular system my team inherited gave us nothing but
         | issues: cluster coordination issues, so quorum wasn't met and
         | things wouldn't start cleanly, network partitioning issues so
         | nodes would randomly be considered dead, actors "becoming" (the
         | term used IIRC) other types of actors based on messages
         | received... the whole thing was just.. too ephemeral and
         | organic for our tastes. I used to get excited thinking about
         | systems like that, but I've since grown more conservative in my
         | technology / architectural preferences (i.e. choose boring
         | technology). We actually ended up replacing it with exactly
         | what I suggested: a plain-old set of services talking via a
         | message-broker. It's stupid simple and we've all slept better.
         | 
         | Edit: I will say that the use of actors constrained to a single
         | service to handle concurrency is probably way more supportable
         | than in a clustered mode.
        
           | fearthetelomere wrote:
           | With something like Elixir/Erlang, the distributed system is
           | quite robust and reliable from my experience. A bit rigid and
           | somewhat difficult to configure for custom topologies, but
           | dependable overall.
           | 
           | >a plain-old set of services talking via a message-broker
           | 
           | That said, I think you're absolutely right with distributed
           | Akka. I'm very hesitant to fully embrace it, and we use
           | simple service-level APIs to communicate between nodes. I
           | understand the developers have made a lot of progress on the
           | functionality of remote Akka over the years, but it's just
           | not as tried and true as I would like. Using Aeron for
           | message transport for example, is something that may be the
           | best tool available, but is really hard to sell to my org
           | when simple services are more approachable and maintainable.
           | 
           | >actors "becoming" (the term used IIRC) other types of actors
           | based on messages received
           | 
           | Yeah... I didn't understand why my org was using the Classic
           | Akka instead of the new and improved Typed Akka for a long
           | time. But cool-looking things like this just aren't worth it
           | sometimes. Especially when Classic Akka "just works".
        
       | waffletower wrote:
       | Investment in STM (Software Transactional Memory) through
       | implementation of supporting data structures, could be a more
       | effective investment for this problem space.
        
         | fiddlerwoaroof wrote:
         | Clojure's STM is basically unused: from what I can tell, STM
         | turns out to be better in theory than in practice.
        
           | lilactown wrote:
           | The problem IMHO is that there aren't a lot of problems that
           | are particularly suited to STM.
           | 
           | I can't think of many instances where I would use STM over
           | CAS (e.g. an atom in Clojure); and the times I have needed
           | something akin to STM (e.g. building an incremental dataflow
           | engine with transactions) I wanted more control over the
           | runtime behavior than Clojure's STM provided.
           | 
           | Plenty of business systems need transactional guarantees and
           | either durability or distribution (or both), which makes an
           | external store like Postgres or Redis a ton more attractive
           | than STM within a single process.
        
             | breatheoften wrote:
             | Some manner of pluggable STM protocol to define a standard
             | programming model on top of conflict detection would be
             | pretty nice tho imo.
             | 
             | Features like postgres's serialized transaction isolation
             | -- which as a non expert I think of as basically database
             | implemented STM -- are really flexible -- but most
             | ecosystems programming models don't really expose this
             | capability in a full proof and natural way. You have to
             | work to too hard to take full advantage of the capability
             | ...
        
       | toddh wrote:
       | Once you have actors it helps to have a priority mechanism,
       | latency guarantees, a scheduling abstraction so work can be
       | partitioned, some sort of boost mechanism to prevent starvation,
       | a timer abstraction, and a state machine abstraction to carry out
       | work flows.
        
       | DelightOne wrote:
       | Currently active review:
       | https://forums.swift.org/t/se-0306-actors/45734
       | 
       | Review by Chris Lattner:
       | https://forums.swift.org/t/se-0306-actors/45734/4
        
         | gigatexal wrote:
         | Chris's review is really impressive. Anyone doing code review
         | should take note.
        
       | wrren wrote:
       | Over a long enough timeline, all languages converge on the Erlang
       | feature set!
        
       | qaq wrote:
       | I really like how Swift is shaping up. They keep making choices
       | that imho give you good balance of ergonomics and performance.
        
         | blacktriangle wrote:
         | I can't help but feel the opposite, as if Swift is a dog
         | chasing cars. Function builders are a really awkward
         | unnecessary feature that was implemented so that SwiftUI could
         | have a decent looking DSL. Some types showed that the whole
         | protocol oriented programming model breaks down in some serious
         | ways. And now they are looking at doing actors as a whole new
         | built-in functionality rather than just a concurrency library.
         | It looks like the Swift language is just too rigid and unable
         | to evolve in useful ways without the blessing of the language
         | developers themselves.
        
           | ckok wrote:
           | I can't help but get the feeling that plan with Swift is to
           | be the only language you can effectively use for Apple
           | platforms, but also is probably going to be the language that
           | will only be used on Apple platforms because of Apple's whims
           | like the function builders.
        
             | qaq wrote:
             | Realistically if choosing between C++, Rust, Go and Swift
             | for things that are not highly performance sensitive I
             | would happily go with Swift.
        
               | cmollis wrote:
               | agree.
        
           | ragnese wrote:
           | > Function builders are a really awkward unnecessary feature
           | that was implemented so that SwiftUI could have a decent
           | looking DSL.
           | 
           | Ugh. I agree. I haven't actually _used_ SwiftUI in anger yet,
           | so I try to reserve my judgement, but the whole thing seems
           | like a lot of magic and complexity to me (not to mention
           | reports of some performance issues /gotchas).
           | 
           | Didn't they also add some weird dynamic JavaScripty property
           | getters or something?
        
             | blacktriangle wrote:
             | Yep, property wrappers:
             | https://nshipster.com/propertywrapper/
        
           | afavour wrote:
           | I really enjoy working with Swift but after looking at this
           | Actor proposal I think I agree with you. It seems like you'd
           | always want to use actors? Unless you specifically don't want
           | things to be concurrency safe. It feels like something the
           | language should have had from the start or should have as an
           | external library.
        
             | ogre_codes wrote:
             | > It seems like you'd always want to use actors?
             | 
             | My impression is that when working with Swift your first
             | tool of choice should be a value type, so a strict or an
             | enum. Actors would only be desirable when you need class-
             | like behaviors and need concurrency. Maybe I'm missing
             | something, but I suspect many of us will never use actors
             | directly at all. I certainly don't see any parts of my code
             | which demand this kind of structure.
        
           | slavapestov wrote:
           | > Some types showed that the whole protocol oriented
           | programming model breaks down in some serious ways.
           | 
           | How so? Rust has an equivalent feature (impl Trait) for
           | example. It solves a legitimate problem.
        
           | raspasov wrote:
           | Agree. Either choose to use lisp syntax and lisp macros or
           | add all the language "features" ad-hoc one by one over the
           | years.
        
         | ragnese wrote:
         | I feel like it's really lame that its Swift version 157 or
         | whatever and they still don't have a stable async/concurrency
         | story besides callbacks. What's more is that they actually
         | chose an error handling mechanism that doesn't even _work_ with
         | callbacks /closures! So sometimes you have a throwing function
         | and sometimes you return a Result.
         | 
         | As much as I actually do enjoy working with Swift (real type
         | classes!!), there are some parts that are a big WTF.
        
           | ogre_codes wrote:
           | > I feel like it's really lame that its Swift version 157 or
           | whatever and they still don't have a stable async/concurrency
           | story besides callbacks.
           | 
           | It is frustrating, but it seems like they are _finally_
           | getting there. It's frustrating since a language like Go had
           | a good concurrency model almost from the start. But Go had
           | different constraints and arguably has less surface area to
           | cover.
        
           | slavapestov wrote:
           | > they still don't have a stable async/concurrency story
           | besides callbacks. What's more is that they actually chose an
           | error handling mechanism that doesn't even work with
           | callbacks/closures! So sometimes you have a throwing function
           | and sometimes you return a Result.
           | 
           | This is exactly what the new async/await feature solves
           | though. Actors are built on top of that.
        
       ___________________________________________________________________
       (page generated 2021-03-16 23:00 UTC)