10 Years Ago: Apple Announced Swift
10 year anniversary of Swift being announced at WWDC.
Wow that’s right. This was a big day and Swift has come a long way in the intervening decade: Congrats to everyone who has driven it forward to support such an amazing tech platform! 🍎🐣
Interesting to go back and watch this presentation and see how Swift was originally promoted ten years ago. I would certainly say that Swift has been a huge success. On the other hand, I’m personally still 100% programming in Objective-C and that continues to be an excellent development environment for building a sophisticated Mac app.
My high-level take is that I generally like programming in Swift. I’m rewriting all my apps in it. But I’m not sure it was the right thing to build. It’s been such an immense effort both within Apple and for the community. This has been a distraction from apps, frameworks, architecture, and documentation. So much mindshare has been taken up by the language itself, which should be just a tool for building the things that actually matter for our customers. It’s come a long way, but the “end” is not yet in sight, as, even 10 years in, essential pieces are still being designed.
I think it’s quite possible that most of the parts that I, as an app developer, care about could have been had—sooner, and with greater tools speed and reliability—with a less ambitious project that actually tried to be Objective-C without the C, rather than a more static mega language that tries to replace C, C++, Objective-C, and Rust. The question is not how Swift 5.10 compares with Objective-C 2 but how it would compare with the hypothetical Objective-C n or Objective-Mojo that we could have had instead.
It all comes down to the big vision of world domination and having a single language from the bottom of the stack to the top. That would never have happened with a more pragmatic evolution of Objective-C. If that eventually pans out, and Swift ends up being good at all levels of the stack, that would be a triumph. But, here in 2024, it still seems like a very long way away. In another 10 years, I suspect that XNU and WebKit will still be mostly C and C++, and the app frameworks will still have large amounts of Objective-C (or C++ in the case of SwiftUI).
Now let’s look at some specifics. The good:
Overall, it’s very ergonomic. I like the syntax. Basic type inference works well. Most of my code is more concise and readable. It’s generally fun to program in, in the way that people often talk about scripting languages like Ruby and Python.
Objective-C/Cocoa interop works really well. I can access (almost) all of the old APIs, and they look and feel better than before. Bridging overhead is in most cases not an issue. Though it’s not as flexible as migrating Objective-C code to ARC, it is possible to incrementally convert an existing project to Swift.
Optionals are really great.
I feel encouraged—because of the low ceremony—to do the right thing in terms of defining new types where they make sense and splitting up large classes. I don’t have to maintain header files or write lots of boilerplate.
Error handling works well, has low overhead, and manages to be clear without being burdensome.
I like having more tools to structure and process my data: enums, tuples, structs, and pattern matching.
Extensions on non-class types are really useful.
I like being able to add implementations in protocol extensions, a limited but very pragmatic form of multiple inheritance.
Performance of the compiled code can indeed be very swift. I’m very happy with how
Data
lets me work at a high level but then optimizes down to very low overhead.The standard library is well designed and provides lots of useful functionality. They seem to have gotten Unicode strings right.
I like
let
/var
and the overall way of handling value types and CoW collections.ARC mostly does the right thing and stays out of my way.
Standalone .swift files work well as scripts.
The bad:
I had high hopes given how awesome Clang is, but the Swift compiler has been a disappointment. It’s still slow, has terrible error messages, and is unreliable (crashes, spurious errors, frequent need to clear derived data and/or relaunch Xcode). The compiled binaries are huge. It seems like in designing the type inference and optimizer plan that they made a bet on being bailed out by compiler tech that did not yet exist and mostly lost. Now it’s too late to fix.
The greatest potential was always for new Swift-only frameworks that would not have been possible otherwise. The jury is still out, but overall I do not like what I’ve seen from SwiftUI. So far it seems less capable, and the code seems brittle. It’s not clear to me that the more static/declarative approach is a good fit for UI stuff. SwiftData is also not encouraging in that it seems incredibly buggy and limited compared with Core Data, with only minor advantages due to being Swift. Swift Concurrency makes tradeoffs analogous to static vs. dynamic typing, and it’s not yet clear whether this was the right decision.
More generally, the Swift-forward API design—as with SwiftUI, Swift Regex, and format styles—seems to lead to systems that are harder to document and learn. There are lots of little interacting pieces, in scattered types and extensions. How do they all fit together? Where do you look to find a particular feature? There’s been a lot of talk of progressive disclosure, but I’m not sure that was actually achieved.
The core selling point of more reliable code seems to have been realized in the micro but not in the macro. That is, any given class or function is probably more solid due to more precise typing and handling of nulls and errors. But I find the overall quality and reliability of Apple’s apps, frameworks, and tools to be much lower now than before the introduction of Swift. I think this is mostly not because of Swift, but it’s certainly not a win yet.
The other main selling point of speed has been partially realized. Some stuff can be much faster than Objective-C. But in other cases there’s more overhead for mandatory ARC and slower runtime checks. Sometimes code needs tuning to get rid of overhead from exclusivity checking and bridging. Overall, I would say that for most code there is not a huge difference either way. Port your old code because you like the language or the new APIs or you are rearchitecting, anyway, not to magically make the same old design faster.
Playgrounds seemed like such a good idea, but they just don’t work very well. I tend to do my exploratory work in test methods or small projects instead.
I guess Swift has really advanced the state of the art with generics and protocols, but I still feel like they get in the way a lot and sometimes prevent me from being able to write what I want to write. Whereas general Swift code is more concise than the equivalent Objective-C, generics often create verbose messes. In some places, like with tests or integrating with Objective-C, you can’t use generics at all, and in other places they can “infect” other layers of code that shouldn’t really need to know about them. Basic generics, like with collections in the standard library, work well. The problems come when trying to do more “dynamic” stuff. Enhancements are making more and more things possible, but it’s not easy or pretty.
C interop is confusing for those of us who only dabble in it occasionally. It’s hard to know how to satisfy the compiler and even harder to know whether you’ve done so in the right way. Part of this is surely C’s fault, but the end result is that I don’t want to rewrite my C code in Swift the way I do want to rewrite my Objective-C code in it.
Swift has terrible handling of deprecated APIs and, in general, suppression of warnings.
Namespaces feel half-baked.
The complexity of the language is ever-growing. I suppose that this was inevitable given the vision of being all things to all people and the need to give the compiler more static information so that it can verify what you’re doing. If Objective-C was a small language with most of the important stuff in libraries and creative use of the runtime, Swift seems to put everything into the language itself. That means ideas can’t come from anywhere; you need the technical and political chops to modify the compiler. Macros may improve this somewhat, though they also have a high barrier to entry.
Auto-indent in Xcode seems to often do the wrong thing and isn’t consistent between versions.
Though Swift is clearly here to stay, and has attained a hip/cool aura, it has not really had the hoped for uptake on the server and other non-Apple platforms.
Previously:
- SwiftData Issues in macOS 14 and iOS 17
- Dynamic Swift Predicates in macOS 14 and iOS 17
- Swift FormatStyle Issues
- Swift Proposal: Objective-C Implementations in Swift
- Xcode 15.4
- Mac Dialog in Auto Layout vs. SwiftUI
- Swift 5.10
- SwiftData
- A Vision for Using C++ From Swift
- Mojo Programming Language
- Equality in Swift: NSObject, Subclasses, and Existentials
- Swift Regex
- Why Lattner Left the Swift Core Team
- Chris Lattner Is Leaving Apple
- “It’s a Coup”
- Swift Links
Update (2024-06-05): See also: Hacker News.
I’d say what I like most about Swift is
Optional
. It is simple to use (especially since we gotif let x {}
) but gives one a warm feeling of not missing a nil.I 100% agree with each and every point in the bad list.
Thinking of integer index for string, I’d add a “Stubbornness of the language guardians” (phrased as “Strict adherence to a clean design.”) but I do not disagree with any of the points that are on the list.
I agree with Michael’s take but to me the jury is still out on performance. It’s clearly not competitive against C++.
Update (2024-06-06): See also: this Swift roast and Nathan Manceaux-Panot.
Swift is 10. I think at 7 or so I asked whether it felt it was as mature as ObjC/Cocoa were at that age. I have a different question now. Where do we think Swift will be in 10 years? Will SwiftUI actually be capable of making a real Mac app? Or will we have a new language and/or framework by then (20 years after Swift). Or will the Mac maybe just no longer exist by then, making this question moot?
There’s 2 separate worlds of software development.
Building apps and user facing features.
Infrastructure and low level language design.
Swift concurrency (and a lot of Swift actually) just looks to me like evidence the language people being given far too much power, to run away with architecture astronauting projects.
Apple banning employees from developing their own apps has many negative effects and this is one of them.
The parts of Swift Concurrency that make me more productive when building apps are Async/Await and maybe MainActor. Everything else is more work for little benefit, making it impractical.
Update (2024-06-07): See also: Reddit and Lobsters.
- The language delivered on core promises of better architecture, reduced crashes, more semantic types
- The compiler is simply not adequate, it is barely functional and Apple has failed to invest in it sufficiently
- Initiatives like WASM, server-side are exciting but hamstrung by the BDFL problem making it difficult to widen the ecosystem like in Rust, JavaScript, etc
- Swift is still just “the language for Apple dev”, not a true C-level player like Rust
Update (2024-06-19): Andy Finnell:
After 10 years of Swift, I still get compiler crashes on the regular. Xcode should at least make them actionable.
The compiler logs give instructions on how to file a bug report. It should just be a button I can press.
The compiler logs give zero indication of what’s causing the crash. Xcode should have a command that runs a bisect over the file causing the crash until it’s identified the offending lines. i.e. automate what a human would do by commenting out code.
Daniel Hooper (via Hacker News):
The Swift compiler can take an absurdly long time to compile expressions due to how types are inferred. Here’s an explanation by the creator of Swift, Chris Lattner (from from his Mojo talk [Hacker News] and edited for clarity):
My experience with Swift is we tried to make a really fancy bi-directional Hindley-Milner type checker and it’s really great because you can have very beautiful minimal syntax but the problem is that A) compile times are really bad (particularly if you have complicated expressions) and B) the error messages are awful because now you have a global constraint system and when something goes wrong you have to infer what happened and the user can’t know that something over there made it so something over here can’t type check. In my experience it sounds great but it doesn’t work super well.
[…]
Swift 6 spends 42 seconds on these 12 lines on an M1 Pro, only to spit out the notorious
error: the compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions
. In the same amount of time, Clang can perform a clean build of my 59,000 line C project 38 times. The Swift standard library has 17 overloads of+
and 9 types adopting theExpressibleByStringLiteral
Protocol. This leads to an exponential combination of types and operators for the constraint solver to try.
Even very short snippets of code can trigger that error message, and compilation is also slow even for code that doesn’t trigger it.
People seem to be blissfully unaware of just how many resources go into making yearly OS updates happen. An anecdatapoint I’ve heard thrown around is that the introduction of Swift into Apple’s codebases more than doubled the time it takes to build all of Apple’s OSes every night across their build farms, to the point where it now takes a day and a half to run a ‘nightly’ build.
Scrub a little earlier for more details on the problems with unpredictable performance.
In May 2015 (so still in the Swift 1 days) I wrote a version of Peter Norvig’s simple spelling correction generator. I happened to think of it again and thought I’d try updating it to use all the improvements to Swift that have happened since then.
See also: Reddit, The Talk Show.
Update (2024-06-25): See also: Hacker News.
Ocaml is really fast to compile when I play with toy projects. It’s a fairly simple type system compared to, say, TypeScript (I’m not familiar enough with Swift to know how it compares to Ocaml in terms of type system complexity). I’d prefer the simpler language if it means faster compilation.
My protobuf schema now needs ~30 seconds to compile on the Swift side.⏳
Update (2024-07-15): Chris Lattner discusses progressive disclosure and Swift’s complexity (via Hacker News):
Swift, the original idea was factor complexity (…) massively failed, in my opinion (…) Swift has turned into a gigantic, super complicated bag of special cases, special syntax, special stuff
[…]
instead of fixing the core, what the team did, both when I was there, so partially my fault, but also subsequently, is they started adding all these special cases (…) a lot of this stuff got added under extreme time pressure to enable a feature like SwiftUI. And there’s a bunch of stuff that feeds into that, as well as just the language gets more and more and more and more complicated.