4 ms·
This just doesn't match with my experience of Swift. My experience is a language that is well designed, at times feeling too complex, but always justifying that
by danpalmer 2y ago
This just doesn't match with my experience of Swift. My experience is a language that is well designed, at times feeling too complex, but always justifying that complexity with correctness when I dig into the reasons. Most of the language is driven by an open process, to the point that language announcements at WWDC are only a recap of the last year of accepted enhancement proposals.
"A great language strangled by governance" – it's not clear to me that Swift is in a materially worse place than any of the 3 alternatives this post points to. Rust has had a lot of drama and botched their async/await, Python had 3, took a decade to recover, and has failed to address its terrible packaging over the last 2 decades, and the Kotlin process described sounds almost identical to the Swift process.
Was Swift entirely top-down controlled at the beginning, with a bunch of breaking changes? Yes, but it has very clearly graduated from its early development now with no forced breaking changes and an open proposal process that is clearly working. Has Swift hard-coded Apple framework exceptions? Maybe, but that has never gotten in the way of me using or understanding Swift code, so I'm not sure it affects me as a developer. Has Swift become a hugely complex compiler? Sure, but I'd rather have a complex compiler and a better developer experience, especially if Apple is paying for it.
I don't disagree with the facts here, this just doesn't resonate with me at all. I'm a very happy Swift user, would like to be using it a lot more, and enjoy the forward momentum in the ecosystem as Swift becomes in my mind one of the most advanced languages available.
- skavi 2y agoNot to your main point, but I don’t think it’s fair to say Rust “botched” its async impl. There are certain features it’s missing, but nothing about the design really prevents them from being added. And many have been in the past few years. I’d point to the “leakpocalypse” as a more fundamental Rust flaw.
- adastra22 2y agoHaving perpetually colored functions is a huge, fundamental annoyance with the Rust concurrency design.
- nine_k 2y agoWhat would be a good way to not have sync / async colors? Explicit yield / resume, like Lua? Full-on CPS?
- adastra22 2y agoGo handles it quite nicely. It's not perfect, but it is nice. Every function is a coroutine. There is no such thing as a non-async fn in Go. But if you want explicit await-like concurrency, then you can explicitly wait on a message from a channel. Every time I bring this up there are people who jump in with excuses for why Rust can't do something similar. But these are either (1) historical accidents in the sense of implementing goroutines would've broken existing code [fair], or (2) excuses. Go's approach is much harder to get right, and much more pervasive in the impact on the language. But when it's done well, it's really smooth to use. I use Rust as my daily driver because I want the safety guarantees that Rust gives, and cargo is pretty nice. But every time I need to do something highly concurrent, I wish I was working in Go...
- gulbanana 2y agoThere is a good reason why Rust can't do it the Go way - Go's always-async concurrency requires a fairly heavy runtime. Rust is designed to be able to support systems that have no runtime at all, or a specialised one. (https://embassy.dev/ https://embassy.dev/ is an example of a specialised async runtime for running async Rust on microcontrollers).
- adastra22 2y agoWhy wouldn't you be able to swap out the concurrency runtime for something else? Or not switch it off entirely when not needed (making the concurrency keyboards into syntax errors)?
- zarzavat 2y agoYou can, you can switch it off by declaring a normal non-async function. It's almost as if there's two fundamentally different types of functions that people might want to declare, necessitating two function colors. Go is a language that is primarily used for async programming, so the design of having everything async makes sense. Rust is a language that is primarily used for sync programming, async programming is catered for but it's not the focus of the language. So having everything be async doesn't make any sense at all.
- danpalmer 2y agoThat may be more fair. I guess a better way of putting it is that the async/await implementation was fraught with drama and that it did not really succeed in getting the whole community onboard and pulling in the same direction. Python, for example, continues to have similar issues, whereas Node/JS definitely did stick the landing, and Swift arguably did too.
- skavi 2y agoYup, that’s an entirely fair characterization. One I probably should have understood from your initial comment :).
- liuliu 2y agoYeah. I think "keyword" is less of an issue personally. At the end of the day, if we want to approach things like async / await and ownership, I would prefer "consume / borrow" than some particular symbols. That has been said, I do worry that there are too much runtime stuff built into the language, and it doesn't seem there any desire to clean it up. Newer things like actors that people argues cannot be done as library brings runtime into the language. autograd is in the similar vein. Even automatic-reference-counting (a.k.a. classes) would be nice to move that out of core language. The end result is that Swift is a huge project for people to maintain, in both the compiler land and the runtime land. I am happy that Apple is paying for it, but ...
- jarjoura 2y agoI do find it quite unsatisfying the way the actor executor is somehow magically generated at compile time, without any way to build your own in Swift. It's also not obvious that actors are re-entrant until you stumble into it. It's quite interesting the way the swift compiler gets around its own complexity by wrapping core functionality as llvm builtins whenever the engineers hit a wall. Is it an abstraction? Not really sure what to call it, but I'm finding it becomes a very leaky design after working in large Swift codebases. Sure, there is always intentionality behind the decisions that get made, and not saying it its sloppy, it's not. However, every single language design decision feels one-off, and in 2024, the language is now made up of hundreds of little one-off decisions that somehow still work out okay.
- liuliu 2y agoYeah. I guess that I misspoke a little bit. I am not even criticize actor (as in Go, there is a relatively "heavy" runtime to implement its green thread too). I was originally thinking about distributed actor proposal (and implementation) and forget to spell that out. > It's also not obvious that actors are re-entrant until you stumble into it. Yeah, this part is annoying. While understandable from runtime implementation perspective, it feels like a big mistake need to be corrected in the future. > the language is now made up of hundreds of little one-off decisions that somehow still work out okay. There are some fixes on these decisions, some times. For example, `some` / `any` fixed some associated type related weirdness that you need to workaround (this is a huge improvement for me at least). But some other problems remains: the existence of existential type is not obvious at all and can cause issues. For example, a closure type is not existential, and cannot be extended. This is OK most of the time, but then UnboundedRange is defined as a closure: https://developer.apple.com/documentation/swift/unboundedrange https://developer.apple.com/documentation/swift/unboundedran... so you cannot extend that easily (which would be ideal if you want to extend PartialRange / ClosedRange / UnboundedRange to do something like, return Python slice object?). I think this / or similar issue also made things like tuples to automatically conform to Equatable / Hashable protocol not easy to do, which is not big problem, but minor annoyance.