News for hackers. Stuff that matters.
Re:Chris Lattner left Swift core team by ragnese on Monday February 21, 2022 @01:12PM (#30418818)
> A few years ago that seemed to start to change. From my perspective, some of the features added to the language to support SwiftUI - specifically property wrappers and function builders - very much felt rushed and forced into the language based on external deadlines.

Yep. If anyone had doubts that the language was no longer the one Lattner designed, SwiftUI should've put the nail in that coffin.

Swift is an imperative, statement-oriented, language. In fact, I get kind of frustrated when writing Swift after spending some time with Rust: I just love writing `let x = if foo { 1 } else { 2 }` or `let x = match foo { ... }`, and it's ugly as hell to try to assign a variable from a switch statement in Swift, etc. BUT, that's okay- I'm almost sure that zero programming languages were written with my opinion in mind, and Swift is Swift.

But, SwiftUI is declarative, which just doesn't work with literally the entire rest of the language. So they added result builders and these weird, magical, annotations just so we can have a UI DSL.

Error handling is now inconsistent and annoying, too. The original approach was to use this quasi-checked-exception syntax where you mark a function as `throws`, and all callers are forced to handle the possibility of failure. The difference between this and Java's checked exceptions is that the specific error type is not part of the signature and therefore the caller only knows that they might get an Error, but not what specific type of Error.

They even have a mechanism for higher-order functions to indicate that they don't throw any of their own errors, but will re-throw errors thrown by function arguments. Clever.

Okay, fine. Pros and cons to that approach, some like it, some don't, etc, whatever. Except then they realized that this approach falls flat in some scenarios (async/promises), so we really just need to go back to returning error values. So they stabilized a Result type.

So, now we need to figure out when we're writing a function if we want to return a Result or make it throw. And, even more annoyingly, Result has a specifically-typed error variant! It's actually a Result<T, E>. Which is it, Swift team? Should immediate callers care about specific error types or not?

Just recently, they landed the async and Actors stuff. Async is fine and great, and is consistent with the imperative syntax and semantics of the language, and it even supports `throws`, IIRC. But Actors? What the hell is that? That's totally out of left field for the rest of the language.

I used to really enjoy Swift in the 2.x to 3.y days, but it really seems like it doesn't even know what it wants to be as a language anymore, which is a real shame- it had a real shot to take the wind out of Rust's sails, IMO (The number one "scary" part of Rust is lifetimes and borrow checker. Swift has CoW structs and auto-ref-counted classes, instead, which can be seen as more appropriate for higher level tasks than writing system libs, etc).

Re:Chris Lattner left Swift core team by honkdaddy on Monday February 21, 2022 @02:33PM (#30419662)
I totally agree. I've been writing varying levels of Swift code since the 1.0 days and I truly can't think of a time I've felt constrained by not having the actor keyword. The threading and DispatchQueue APIs are so rich and flexible already, I just don't really see the use case. Maybe someone who's worked more with them can chime in?
Re:Chris Lattner left Swift core team by ninkendo on Monday February 21, 2022 @09:09PM (#30423288)
A good critique of libdispatch is here: https://tclementdev.com/posts/what_went_wrong_with_the_libdi...

I think the main issue with GCD is the potential for deadlocks in serial queues (which it doesn’t really help you with), and the related problem of thread explosion in concurrent queues.

Actors make protecting shared mutable state really easy, solving a big chunk of the reason you’d want to use semaphores and serial queues in the first place. If you stick with async/await/Task{}/actors, you’re guaranteed to only have the optimum number of threads that can saturate cores, and won’t have deadlocks. If you use Sendable properly and heed all the warnings, you’re a good way towards the kind of “fearless concurrency” that Rust gives you. It really is pretty great IMO compared to GCD.

Re:Chris Lattner left Swift core team by saagarjha on Wednesday February 23, 2022 @05:14AM (#30439610)
I’ve been using Swift Concurrency for the last several months and while it has a lot of nice things going for it there’s still a lot of ways you can “hold it wrong” and get incredibly poor performance. If you block a thread in the thread pool you’re going to deadlock. It’s still pretty easy to create data races (possibly with mis-annotated or poorly thought out types). And logical races are absolutely still a thing, and I might even say they are more common because the messaging is that this’ll magically solve all your concurrency problems and it doesn’t do that.
Re:Chris Lattner left Swift core team by ninkendo on Wednesday February 23, 2022 @08:36AM (#30440787)
> If you block a thread in the thread pool you’re going to deadlock.

I’m actually happy with this decision… it was very much done intentionally to prevent the kind of thread explosion that is all too common in GCD. The criticism of GCD I linked to was very skeptical of actors for this reason; if the implementation decides to add more threads to avoid deadlocks, you get the same performance pitfalls as in GCD, and thankfully that didn’t happen.

In practice, I’ve found that avoiding deadlocks is as simple as grepping for `DispatchSemaphore|DispatchGroup` in your codebase and eliminating them with extreme prejudice. If you stick to Tasks/TaskGroups/Task.sleep, there’s no real possibility of accidentally introducing deadlocks unless you try really hard to do so.

And yeah, logical races can still happen in actors, but it’s easy enough at a glance to tell whether you’ll run into one… if you avoid using `await` in a section of code that needs to run exclusively, you’ll be fine. (Even with `await` calls you may get lucky if there’s no actual suspend point happening, but a quick and dirty rule is just “don’t call await and your code will never be run concurrently.”)

Re:Chris Lattner left Swift core team by saagarjha on Wednesday February 23, 2022 @08:53PM (#30449357)
> I’ve found that avoiding deadlocks is as simple as grepping for `DispatchSemaphore|DispatchGroup` in your codebase and eliminating them with extreme prejudice.

You’d think so but then you realize that framework code you call into might decide to do this and you wouldn’t know until it deadlocked. On a 6-core iPhone 13 this is probably not going to be noticeable, but that’s probably not true on a 2-core iPhone 6s…

Re:Chris Lattner left Swift core team by ninkendo on Wednesday February 23, 2022 @10:41PM (#30449946)
Framework code you call into can block so long as it makes forward progress. Deadlocks happen if you lock a thread in the shared Concurrency thread pool, and expect some other code running in the same thread pool to do the unlocking.

But if you’re calling into framework code which is using GCD, the queues it dispatches into will be run on a separate GCD thread pool. If said framework code is using a semaphore or lock to block your calling (Concurrency) thread, then it stands to reason there’s another thread in the GCD pool which will eventually unlock it. (Or else it’s a deadlock no matter what you do.)

I haven’t come across any framework code which violates this, although maybe you’ve run into problems I haven’t.

Re:Chris Lattner left Swift core team by skohan on Monday February 21, 2022 @02:54PM (#30419844)
I think the motivation for actors is that it's an abstraction which lets you write concurrent code with reasonably strong safety guarantees without adding as much cognitive overhead as a strict system like Rust. GCD is a really nice abstraction for async, but it doesn't protect you from shooting yourself in the foot if you're not careful about what thread is doing what.

That said, I'm really not sold on actors. I think CS as a whole hasn't really landed on the right abstraction for concurrency yet, actors seem a bit experimental, and GCD is plenty good enough in most cases.