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