The Swift team has officially announced the availability of Swift 6, a new major version of Apple open-source language with focus on low-level and embedded programming, concurrent code safety, new cross-platforms APIs, and extended Linux and Windows support.
InfoQ has already covered several features brought by Swift 6, including Embedded Swift, a compilation mode that aims to address the specific constraints of embedded devices and kernel-level code; Swift Testing, a new cross-platform testing framework; and the data-race free safe mode, aimed at helping developers create concurrent programs free of data races thanks to a new compile-time static detector.
Other major new features in Swift 6 are typed throws, memory ownership extensions for generics, 128 bit integers support, and extended C++ interoperability.
Typed throws enable the specification of the type of errors a function can throw as part of its signature. So, instead of declaring a generic throw clause,
func parseRecord(from string: String) throws -> Record {
// ...
}
you can now explicitly declare the error type. This will bring the additional simplification that when you wrap the call to such a function in a do...try...catch
block, the type of the error is already known at compile time:
func parseRecord(from string: String) throws(ParseError) -> Record {
// ...
}
// call site:
do {
let record = try parseRecord(from: myString)
} catch {
// 'error' has type 'ParseError'
}
Interestingly, all Swift 6 functions have a typed throw signature under the hood. Indeed, a function with a non-typed throws
is equivalent to a function throwing Any Error
, while a non-type throws
is equivalent to throws(any Error)
.
It is important to stress that this feature is not meant to replace non-typed throws everywhere.
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.
In fact, according to the the authors of the evolution proposal "the existing (untyped) throws remains the better default error-handling mechanism for most Swift code".
The new memory ownership model has been introduced in Swift 5.9 and Swift 6 brings it a tad further by extending support for generics "move only" types.
The concept of ownership is functional to controlling which piece of code is responsible for a given value to be eventually destroyed. Until Swift 5.9, Swift memory model was not exposed to programmers, as it was the case, e.g., with manual reference counting in Objective-C. Rather, it was encoded in a set of rules that worked pretty well in the general case, but made it harder to get more control on how values were destroyed using the default reference counting algorithm.
Without going into much detail, the memory ownership model exposed in Swift 5.9 is based on the concepts of borrowing
and consuming
, which allows customization of how initializers and functions treat ownership of the arguments they receive and, therefore, modify Swift default assumptions that initializers get the ownership (hence, consume) while functions do not (hence, they borrow).
An integral part of this model is represented by the "non copyable" protocol, which is used for "move only" types, i.e. a type whose values always have a unique ownership and cannot be copied. The implementation of the protocol in Swift 5.9 could not be used with generics, protocols, or existentials, but Swift 6 fills this gap by extending it. Covering the details of ~Copyable
for generics goes beyond the scope of the present article, so check out the linked Swift Evolution proposal for more details.
Related to the ~Copyable
protocol, Swift 6 leverages it to extend C++ interop to move-only types. If a C++ class has no copy constructor, Swift assumes it is ~Copyable
, with the possibility of explicitly ignoring an existing copy constructor using the SWIFT_NONCOPYABLE
annotation. In addition, virtual methods, default arguments, and more standard library types such as std::map
and std::optional
are now supported.
Speaking of platform support, Swift 6 can be used now on more Linux distributions, including Amazon Linux, Debian, Fedora, Red Hat, and Ubuntu, and Windows x86_64 and arm64 architectures. On Linux, the Swift 6 SDK supports building fully statically linked executables with no external dependencies and cross-compiling from other Linux platforms.
There is a lot more to Swift 6 than can be covered here, so do not miss the official announcement for the full details.