[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)