Monday, July 22, 2024

Swift 6 Announced

What’s new in Swift:

We’ll briefly go through a history of Swift over the past decade, and show you how the community has grown through workgroups, expanded the package ecosystem, and increased platform support. We’ll introduce you to a new language mode that achieves data-race safety by default, and a language subset that lets you run Swift on highly constrained systems. We’ll also explore some language updates including noncopyable types, typed throws, and improved C++ interoperability.

Migrate your app to Swift 6:

Experience Swift 6 migration in action as we update an existing sample app. Learn how to migrate incrementally, module by module, and how the compiler helps you identify code that's at risk of data races. Discover different techniques for ensuring clear isolation boundaries and eliminating concurrent access to shared mutable state.

Explore Swift performance:

Discover how Swift balances abstraction and performance. Learn what elements of performance to consider and how the Swift optimizer affects them. Explore the different features of Swift and how they’re implemented to further understand the tradeoffs available that can impact performance.

Demystify explicitly built modules:

Explore how builds are changing in Xcode 16 with explicitly built modules. Discover how modules are used to build your code, how explicitly built modules improve transparency in compilation tasks, and how you can optimize your build by sharing modules across targets.

Paul Hudson (list):

2024 is Swift’s 10th anniversary, and for the last five of those years we’ve had no major-version Swift updates – literally half of Swift’s life has been 5.0 through to 5.10.

This is more common than you might think. In fact, several major programming languages have some kind of release that takes significantly longer than all others: Python 3 took years to arrive, PHP 6 took so long the team bailed out and jumped straight to PHP 7, and Perl 6 dragged on so much that it ended up evolving into a different language called Raku.

Swift last had major breaking changes back in Swift 3, but when enabled in full Swift’s own v6 has the potential to make Swift 3 look like a walk in the park. This is partly because of new changes, but partly also because many features added in recent Swift versions have been hidden behind feature flags that will be enabled by default in Swift 6.

Migrating to Swift 6:

Swift’s concurrency system, introduced in Swift 5.5, makes asynchronous and parallel code easier to write and understand. With the Swift 6 language mode, the compiler can now guarantee that concurrent programs are free of data races. When enabled, compiler safety checks that were previously optional become required.

Adopting the Swift 6 language mode is entirely under your control on a per-target basis. Targets that build with previous modes, as well as code in other languages exposed to Swift, can all interoperate with modules that have been migrated to the Swift 6 language mode.

Joe Heck:

There is a lot of great stuff coming in the Swift programming language. I love the focus and effort on validating data-race safety, and is probably the feature set that I’ll spend the most time with. But my favorite new tidbit? Swift 6 now supports a Linux SDK and the ability to compile a stand-alone, statically linked binary.

Alex Grebenyuk:

In recent years, there’ve been some questionable changes, the latest one being Data Race Safety in its current form in Xcode 16 beta.

[…]

If you want to migrate a large codebase to support Swift 6 mode, you need to fix thousands of compiler warnings that become errors once you enable this mode. For example, if you have any global variables, they are now errors.

[…]

In the ideal world, I would love to have more granular control over the types of warnings and errors the compiler produces, depending on what you can tolerate in your project. If data race safety is a compelling enough feature, people will enable it. There are also questions about whether it should be enabled by default and whether its current design can allow it to be enabled by default considering the lack of progressive disclosure.

[…]

Speaking about compile time, one of Swift’s original premises was that it was “fast,” and you would expect it to apply to the compile time. However, with the current slow compilation, developers have to go to extreme lengths to work this around, including reinventing header files by creating protocol-only modules, which Swift was designed to eliminate. If there was a way to disable some of the language features to improve compile time, I would do it in an instant. I’m bringing this up because I wonder what the impact of data race safety is going to be, especially once it gets upgraded with more advanced techniques for eliminating false positives.

Alex Grebenyuk:

For context, it took me months and multiple releases to get this ~4K lines of code somewhat compatible with Sendable and Swift 6. And I now have to revert my concurrency changes in Pulse from last week because I broke some stuff.

I’m farily certain no existing large size codebase will ever be able to fully adopt Swift Concurrency Checking and Swift 6. I would also expect a short-term rise in concurrency bugs in iOS apps.

See also: Jon Reid: A Conversation With Swift 6 About Data Race Safety.

Heath Borders:

I really love Swift the language, but if I had my way, Twitch would only have switched to Swift 2-3 years ago when static linking was easily available.

I got a lot of pressure from other devs to switch back in 2018, so we did, but we had a modularized codebase in Objective-C that we had to demodulalize in Swift bc of no static linking back then. Our clean build times used to be 90 seconds, and now it’s 8 minutes.

[…]

People would be mad if we were still in Objective-C, but I think that’s bc they’d see all the cool stuff at WWDC and wouldn’t be able to use any of it. They’d rightly think they were falling behind the industry. They wouldn’t be as marketable in other jobs.

The main reason for Swift is because everyone else is using it.

Helge Heß:

No, it is because of:

> fighting the direction of the platform, and fighting Apple is generally a losing game

This is IMO not rooted in preferences of developers.

A big issue here is that Apple ties features to the language (and unlike ObjC, Swift has no FFI). The Apple platform developer tooling is a closed system and Apple exploits that to lock devs into their own things over alternatives, regardless of quality.

Previously:

Update (2024-07-23): Drew McCormack:

It is a risky time for Swift. They are channeling enormous resources into solving multi-threading at compile time, but the remedy is worse than the sickness. They are introducing a whole different problem: systemic race conditions. Interleaving of async functions. These are much more difficult to track down IMO. I am literally breaking my head on some of these things. Without a transactional system like dispatch, you end up with something more complex than multithreading.

Update (2024-08-08): Rob Napier:

Every time you write Task, I want you to pretend it's actually this:

Task {
    let delay: Int = (0...10).randomElement()!
    try await Task.sleep(for: .seconds(delay))

    // .. Your code
}

Is your code still correct? I not, then you need to make it correct.

Tasks do not make promises about when they start. Currently, they do not even make promises about whether they start in order (they will, but not quite yet). So if the above addition would break your code, your code is wrong.

Rob Napier:

IMO, no one today understands Swift Concurrency in depth, not even the core team. We’re all kind of feeling our way through it together in public and hoping to discover patterns that are more correct than what we were doing before. There are many great resources for the basics out there, but I don’t think there’s any one resource for how to use this tool “the right way” because I don’t think anyone knows that yet.

Drew McCormack:

The thing about the Swift 6 concurrency bomb is that I know already it won’t catch a single bug. Every error I have to fix is purely to appease the compiler. I see in every case that my code logic is correct, that there is no concurrent access. I also don’t see crashes related to threading (at least not in app level code). Like most static checking dogma, you end up spending a lot of time doing busy work, purely to tell the compiler what you already know.

The irony is that a lot of the solutions to the Swift 6 concurrency errors are to introduce another layer of indirection in the form of an async func. I think it may actually lead to new bugs, rather than fixing old ones. Wouldn’t surprise me if we see problems due to interleaving or data races that weren’t there before.

See also: Marcin Krzyzanowski.

Update (2024-08-13): Thomas Clement:

Apple encouraged developers into updating all their completion hander based functions into async functions which suddenly caused them all to move off the main thread. It was before the concurrency warnings and in the last few years it’s been the number 1 cause of crashes in the projects I’ve been working on. Yes there’s quite a lot of it.

6 Comments RSS · Twitter · Mastodon


The more I hear about Swift, the more it seems like the downsides outweigh the upsides. At least, they may for me, namely because I'm allergic to giving Apple more control over anything. There being a new feature in Swift 6 that you cannot turn off, but you may need to use it in order to use some new feature of something, is exactly the sort of thing I can't stand. The huge compilation times aren't great either.

Almost all of my mac development is done in Objective-C and -- unfortunately -- C++ (I maintain several Qt apps.) I've only done a little bit of development in Swift, and while I appreciate its high level features and find Objective-C's verbosity kind of annoying, I wonder if there's anything deeper I'm missing.


@Bri You can turn it off by running Swift 6 in Swift 5 mode. I suspect that some projects may use that indefinitely.


“ The main reason for Swift is because everyone else is using it.”

Definitely not everyone.


My decision to remain with what I believe is the better language - Objective-C looks better and better. This is interesting too:

https://hachyderm.io/@heathborders/112781006796935411

> What Swift-only APIs are preventing devs from building applications either only in or mostly in Objective-C?

https://mastodon.social/@helge/112781010789221681

> Widgets are the prime example, AppIntents, and the list will increase.

Is that really it? After 10 years?


I want a small, uncomplicated language, with good tooling, and powerful frameworks. They mostly had it. Then they threw it all away to chase trends and academic perfectionism with Swift.

I start new projects with ObjC and Cocoa or UIKit. I never stopped using this S-tier stack. It's kept me most-productive (despite the bugs in the frameworks). I've never moved fast with Swift, be it fighting the type system, or worrying about Swift type inter-op costs, or longer builds, or Xcode crashes, or ghost errors, or some other Swift minutiae or trend ("I wonder if I should use X for this").

If Apple removes ObjC support from Xcode (in a bitter and spiteful attempt to force Swift) I plan to evacuate the Apple dev world. I'm already mentally there. The unfun of the App Store review process, the crippled App Sandbox, security theater, Apple adding new ways to interject at every step of the dev process… if I'm also forced to use C+++ or C+++UI, I'm out.

The best move for Apple would be to start a new language to replace Swift. Maybe it could be ready by Swift 7. Cut 80% of Swift's features, use Foundation as the standard library, and reject the philosophy that led to Swift's complexity. It seems easier than trying to fix Swift.


I mostly see a tooling problem.

Even in Xcode 16, the refactoring, completion/suggestion, inline help, static analysis etc. tooling just seems weak and slow. (Some of the slowness is a result of Apple’s choice to go AOT.)

Compound that with APIs that sometimes favor correctness over convenience (on paper, I like how they think about grapheme clusters, but sometimes all you wanna do is a goddamn character index in a string).

Further compound it with language capabilities like type inference, generics, and macros that can change the entire meaning of something, and make the code hard to pass for the compiler. Swift Testing suffers from this. SwiftUI does as well. You make one little typo or forget one little import, and you get a baffling error that has nothing to do with the underlying issue.

Lots of work ahead.

Just as a random example, handling of modules and type names isn’t good enough. In Rider and VS, it’s much nicer. When I have a file Foo and struct Foo inside, and rename the struct, offer to rename the file. When I rename the file, offer to rename the struct. When there’s more than one type, offer to move the new one to a new file. When I select code, offer to extract it into a function. When I’m calling an extension method, and the module isn’t imported, offer to do that. And so on. Some of this is ostensibly there, but does not work well. Sometimes, offered fixes even empty my file.

IMHO, Swift was the right choice. But Apple isn’t evolving their DX fast enough, and people’s satisfaction suffers as a result.

Leave a Comment