
Community updates
Two new work groups:
Year-round mentorships from now on Swift.org/diversity has more details.
Cross-platform support:
support for Linux package formats: new native (experimental) toolchain installers for Amazon Linux 2 and CentOS 7
Swift news:
dropped dependency on an external Unicode support library, replaced with a faster native implementation
this has made Swift smaller, useful when Swift is statically linked (e.g., in containerized deployments for the server)
now used in Apple’s Secure Enclave Processor
Swift Packages Updates
Trust on first use (TOFU)
new security protocol where the fingerprint of a package is now being recorded when the package is first downloaded
subsequent downloads will validate this fingerprint and report an error if the fingerprints are different
Plugins
Command plugins:
first step in providing more extensible and secure build tools
can be used for documentation generation, source code reformatting, and more
Example:
import PackagePlugin
/// You define a plug-in by creating a struct that conforms to the CommandPlugin protocol.
@main struct MyPlugin: CommandPlugin {
// Add a function that tells your plug-in which tool you'd like to invoke
func performCommand(context: PluginContext, arguments: [String]) throws {
let process = try Process.run(doccExec, arguments: doccArgs) // here we call our tool, in this case DocC
process.waitUntilExit()
}
}DocC: Objective-C and C support
Build tool plugins:
plugins that can implement additional build steps
similar to Xcode Rules
example: source code generation, resource processing
Example:
import PackagePlugin
@main struct MyCoolPlugin: BuildToolPlugin {
func createBuildCommands(context: TargetBuildContext) throws -> [Command] {
let generatedSources = context.pluginWorkDirectory.appending("GeneratedSources")
return [
.buildCommand(
displayName: "Running MyTool",
executable: try context.tool(named: "mycooltool").path,
arguments: ["create"],
outputFilesDirectory: generatedSources)
]
}
}Plugins are declared in a new Plugins folder in the root of our Package, plugins are treated as Swift executables.
Module aliasing
solves module collisions (when two separate packages define a module with the same name)
allows you to rename modules from outside the packages that define them
let package = Package(
name: "MyStunningApp",
dependencies: [
.package(url: "https://.../swift-metrics.git"),
.package(url: "https://.../swift-log.git") // ⚠️ swift-log and swift-metric define a Logging module
],
targets: [
.executableTarget(
name: "MyStunningApp",
dependencies: [
.product(name: "Logging", package: "swift-log"),
.product(name: "Metrics", package: "swift-metrics",
moduleAliases: ["Logging": "MetricsLogging"]), // 👈🏻 module aliasing
])])Performance improvements
Built-time improvements
faster type-checking for generics
Runtime improvements
optimized protocol conformance checking
protocol checking on app startup take as long as four seconds
from Swift 5.7, these checks are cached
for apps that rely heavily on Swift, this means launch-time can be up to twice as fast
Swift driver
program that coordinates the compilation of Swift source code in Swift
rewritten in Swift (last year)
can now be used as a framework directly inside the Xcode build system instead of as a separate executable
this allows it to coordinate builds more closely with the build system to allow things like parallelization
build times improvements around 5-25%
Concurrency updates
further fleshed out the model with data race safety at the forefront
distributedactorsactors in different machines with a network between them
can write a safe backend for your app in Swift
note that a distributed actor call can potentially fail because of network errors
new open source Distributed Actors package that is focused on building server-side, clustered distributed systems in Swift
integrated networking layer using SwiftNIO
implements the SWIM consensus protocol to manage state across the cluster
distributed actor Player {
var ai: PlayerBotAI?
var gameState: GameState
distributed func makeMove() -> GameMove {
return ai.decideNextMove(given: &gameState)
}
}seamless integration with
async/awaithome for time-based algorithms using
AsyncSequencesupport for Apple platforms, Linux, and Windows
Actor prioritization
actors now execute the highest-priority work first
new Swift concurrency instruments
Swift Concurrency view helps you investigate performance issues
Swift Tasks and Swift Actors instruments provide a full suite of tools to help you visualize and optimize your concurrency code
provides useful statistics such as the number of tasks running simultaneously, total tasks that have been created up until that point in time
graphical representation of the parent-child relationships between tasks in structured concurrent code
What’s new in Swift 5.7
Refer to Apple’s Swift repository CHANGELOG.
if let x = xbecomesif let x(optional unwrapping)No need to manually specify a closures result type (closure type inference)
Permitted pointer conversion currently:
| Swift | C | |
|---|---|---|
UnsafePointer<UInt64> const uint64 t * ↔️ UnsafePointer<Int64> const int64 t* | ❌ | ✅ |
UnsafePointer<mailmap_t> const mailmap_t * ↔️ UnsafePointer<UInt8> const char * | ❌ | ✅ |
UnsafeRawPointer const void * ↔️ UnsafePointer<UInt8> const char * | ❌ | ✅ |
Pointer mismatches still possible when passing to C
C++ working group works on improving the interoperation
Special treatment for enabling conversions easily
| Swift | C | Swift calling C | |
|---|---|---|---|
UnsafePointer<UInt64> const uint64 t * ↔️ UnsafePointer<Int64> const int64 t* | ❌ | ✅ | ✅ |
UnsafePointer<mailmap_t> const mailmap_t * ↔️ UnsafePointer<UInt8> const char * | ❌ | ✅ | ✅ |
UnsafeRawPointer const void * ↔️ UnsafePointer<UInt8> const char * | ❌ | ✅ | ✅ |
String parsing currently is hard (especially indices)
“the problem is not the indices expression, it’s the whole function”
Answer: Use Regexes!
Literals supported now with compile-time checks
func parseLine(_ line: Substring) throws -> MailmapEntry {
let regex = /\h*([^<#]+?)??\h*<([^>#]+)>\h*(?:#|\Z)/
guard let match = line.prefixMatch(of: regex) else {
throw MailmapError.badLine
}
return MailmapEntry(name: match.1, email: match.2)
}For those who find Regexes hard to read, new DSL:
import RegexBuilder
let regex = Regex {
ZeroOrMore(.horizontalWhitespace)
Optionally {
Capture (OneOrMore(.noneOf("<#")))
}
.repetitionBehavior(.reluctant)
ZeroOrMore(.horizontalWhitespace)
"<"
Capture (OneOrMore(.noneOf(">#")))
">"
ZeroOrMore(.horizontalWhitespace)
ChoiceOf {
"#"
Anchor.endOfSubjectBeforeNewline
}
}Requires
import RegexBuilderNot a beginner-only feature
turn into reusable
RegexComponent, use from other regexes, even are recursiveno special escaping needed
support literals inside of the builder
types can implement custom parsing logic, like
Date
Regexsupports useful matching functionsCustom engine written in Swift
Compatible with UTS #18 unicode standard
Available in macOS 13, iOS 16, tvOS 16, watchOS 9
Generic code clarity
Assume Mailmap is our generic:
| Something that conforms to Mailmap | A box whose contents conform to Mailmap |
|---|---|
struct EditableMailmap: Mailmap | var map: Mailmap |
<Value: Mailmap> | Array<Mailmap> |
where Element: Mailmap | where Element == Mailmap |
some Mailmap | (Mailmap) -> Mailmap |
We can be more expressive with any:
| Something that conforms to Mailmap | A box whose contents conform to Mailmap |
|---|---|
struct EditableMailmap: Mailmap | var map: any Mailmap |
<Value: Mailmap> | Array<any Mailmap> |
where Element: Mailmap | where Element == any Mailmap |
some Mailmap | (any Mailmap) -> any Mailmap |
easier to explain the difference between methods and understand errors
Swift will now “open the box” for us, so less “cannot conform to” errors
Swift 5.7 fixes the “only be used as a generic constraint” error
you can now specify the types in parameter, without the need to a
whereclause using “primary associated type”
protocol Collection<Element>: Sequence {
associatedtype Index: Comparable
associatedtype Iterator: IteratorProtocol<Element>
associatedtype SubSequence: Collection<Element> where SubSequence.Index == Index, SubSequence.SubSequence == SubSequence
associatedtype Element
}AnyCollectionis a type-erasing wrapper, serves same purpose ofanyanyis a built-in language feature that makes type-erasing wrappers no longer needed in many casessuggestion: replace your wrappers with typealiases, e.g.
let AnyCollection = any Collectionto keep backwards-compatibility (easier migration)Improvements to
anytypes, but still have important limitationsDon’t use
anyall the time, use generics instead, use the top one for better performance (generics)
func addEntries1<Entries: Collection<MailmapEntry>, Map: Mailmap>(_ entries: Entries, to mailmap: inout MailMap) {
for entry in entries {
mailmap.addEntry(entry)
}
}
func addEntries2(_ entries: any Collection<MailmapEntry>, to mailmap: inout any Mailmap) {
for entry in entries {
mailmap.addEntry(entry)
}
}some ProtocolNamesupported in more places, simplifies definition of Generics (simplifies above example, just writesomeinstead ofany)
func addEntries1(_ entries: some Collection<MailmapEntry>, to mailmap: inout some MailMap) {
for entry in entries {
mailmap.addEntry(entry)
}
}
func addEntries2(_ entries: any Collection<MailmapEntry>, to mailmap: inout any Mailmap) {
for entry in entries {
mailmap.addEntry(entry)
}
}

