September 17, 2024
We’re delighted to announce the general availability of Swift 6. This is a major new release that expands Swift to more platforms and domains.
Many people know of Swift as a language for app development, with a million apps on the App Store. But Swift is great for more than just apps. Swift’s safety, speed, and approachability make it a great choice for many other use cases including libraries, internet-scale services, and the most performance-critical and secure code.
Swift 6 scales even further through new low-level programming features, an embedded Swift language subset, expanded Linux and Windows support, new cross-platform APIs including the new Swift Testing library, and more.
Read on for a deep dive into changes to the language, standard libraries, debugging, platform support, and next steps for getting started with Swift 6.
Swift has long offered memory safety, ensuring that variables are initialized before they’re used, memory isn’t accessed after it’s been deallocated, and array indices are checked for out-of-bounds errors. Swift 6 now includes a new, opt-in language mode that extends Swift’s safety guarantees to prevent data races in concurrent code by diagnosing potential data races in your code as compiler errors.
Data-race safety checks were previously available as warnings in Swift 5.10 through the -strict-concurrency=complete compiler flag. Thanks to improved Sendable inference and new compiler analysis for transferring mutable state from one actor to another, Swift 6 warnings about data-race safety have fewer false positives. You can find more information about the Swift 6 language mode and how to migrate at Swift.org/migration.
Swift 6 marks the start of the journey to make data-race safety dramatically easier. The usability of data-race safety remains an area of active development, and your feedback will help shape future improvements.
Swift 6 also comes with a new Synchronization library for low-level concurrency APIs, including atomic operations and a new mutex API.
Swift 6 enables functions to specify the type of error that they throw as part of their signature. This feature is useful in generic code that forwards along errors thrown in client code, or in resource-constrained environments that cannot allocate memory, such as in embedded Swift code.
For example:
func parseRecord(from string: String) throws(ParseError) -> Record {
// ...
}
A call to parseRecord(from:) will either return a Record instance or throw an error of type ParseError. A do..catch block will infer ParseError as the type of the error variable:
do {
let record = try parseRecord(from: myString)
} catch {
// 'error' has type 'ParseError'
}
Typed throws generalizes over throwing and non-throwing functions. A function that is specified as throws (without a specific error type) is equivalent to one that specifies throws(any Error), whereas a non-throwing function is equivalent to one that specifies throws(Never). Calls to functions that are throws(Never) are non-throwing and don’t require error handling at the call site.
Typed throws can also be used in generic functions to propagate error types from parameters, in a manner that is more precise than rethrows. For example, the Sequence.map method can propagate the thrown error type from its closure parameter, indicating that it only throws the same type of errors as the closure: