Swift 5.4 is now officially released! This release contains a variety of language and tooling improvements.
You can try out some of the new features in this playground put together by Paul Hudson.
An updated version of The Swift Programming Language for Swift 5.4 is now available on Swift.org. It is also available for free on the Apple Books store.
Table of Contents
Language Updates
Swift 5.4 includes the following new language features:
- Support for multiple variadic parameters in functions, subscripts and initializers (SE-0284)
- Extend implicit member syntax (SE-0287)
- Result builders (SE-0289)
- Local functions supporting overloading
- Property wrappers for local variables
To prepare the way for a new concurrency model, the compiler now emits a warning and fix-it for unqualified uses of await
as an identifier. Those identifers will be interpreted as the keyword await
in a future version of Swift as part of SE-0296.
Runtime Performance and Code Size Improvements
In Swift 5.4, protocol conformance checks at runtime are significantly faster, thanks to a faster hash table implementation for caching previous lookup results. In particular, this speeds up common runtime as?
and as!
casting operations.
Further, consecutive array modifications now avoid redundant uniqueness checks.
func foo(_ a: inout [Int]) {
// Must do copy-on-write (CoW) check here.
a[0] = 1
// The compiler no longer generates
// a redundant CoW check here.
a[1] = 2
}
Finally, there are a variety of performance improvements:
String
interpolations are more aggressively constant-folded- Fewer retain/release calls, especially for
inout
function arguments and within loops - Generic metadata in the Standard Library is now specialized at compile time, reducing dirty memory usage and improving performance
Swift Package Manager Updates
The Swift Package Manager has several important updates in Swift 5.4:
- Swift packages that specify a 5.4 tools version can now explicitly declare targets as executable, which allows the use of the
@main
keyword in package code (SE-0294) - Swift Package Manager is now supported on Windows!
- Swift Package Manager caches package dependencies on a per-user basis, which reduces the amount of network traffic and increases performance of dependency resolution for subsequent uses of the same package
- Automatic test discovery is now the default on all platforms, removing the need in
LinuxMain.swift
(which has been deprecated) - Multiple improvements to dependencies resolution infrastructure including in manifest loading and caching, leading to improved performance of dependency resolution
- Improved diagnostics infrastructure and error messages, leading to more actionable error messages for dependency resolutions issues and beyond
Windows Platform Support
Support for Swift on Windows has progressed in several important ways:
- Swift Package Manager now works on Windows
- The
WinSDK
module has been extended, covering a greater portion of the Windows developer SDK. This allows more of the APIs to be easily used for Windows applications without having to manually construct libraries to bridge the C interfaces to Swift - Improvements to the installer should make using the toolchain with external tools easier by reducing the flags needed by default on Windows
Developer Experience Improvements
Build Performance
- The Swift compiler is much better at tracking dependencies between files, resulting in a significant reduction in the number of files compiled for many kinds of changes during incremental builds
- Dependencies on member variables and functions of structs, enums, classes, and protocols are now tracked individually by the Swift compiler. This finer granularity speeds and shrinks rebuilds after changes to these entities
- Incremental builds produce deterministic products in many more cases
Code Completion
Code completion’s performance is now much faster within large function bodies. In one example within the swift-package-manager
repository, code completion time for self.
in Swift 5.4 is now 4 times faster (20ms → 5ms) than Swift 5.3, for repeated invocations in that file.
Code completion is also now more reliable in expressions that contain errors, and in expressions that are ambiguous without additional context. For example, given:
func test(a: Int, b: String) -> Int { ... }
func test(a: Int, b: Int) -> String { ... }
func test(a: (Int, Int) -> Int) -> Int { ... }
For the above code, code completion now has the following behavior:
- Invoking code completion after
test().prefix(3).
suggests members ofString
- Invoking code completion after
test(a: 2).
suggests members ofInt
andString
- Invoking code completion after
$0.
in the following block suggests members ofInt
:test { $0. }
Type Checker
Swift 5.4 improves type checking performance for “linked” expressions such as a + b + (2 * c)
For example, consider:
struct S { var s: String? }
func test(_ a: [S]) {
_ = a.reduce("") {
($0 + "," + ($1.s ?? "")) + ($1.s ?? "") + ($1.s ?? "")
}
}
For this code, the type checker completes in under 100 ms, where previously it would time out.
In addition, the type checker has improved performance for nested array literals that contain other literal expressions. For example, the following invalid code would have previously produced a
“too complex to solve in reasonable time” message from the compiler:
enum E {
case first
case second
case third
}
let dictionary = [
.first: [0, 1, 2, 3, 4, 5, 6, 7],
.second: [8, 9, 10, 11, 12, 13, 14, 15],
.third: [16, 17, 18, 19, 20, 21, 22, 23],
]
The Swift 5.4 code now diagnoses this code as invalid with precise error messages:
error: reference to member 'first' cannot be resolved without a contextual type
.first : [ 0, 1, 2, 3, 4, 5, 6, 7],
^
error: reference to member 'second' cannot be resolved without a contextual type
.second : [ 8, 9, 10, 11, 12, 13, 14, 15],
^
error: reference to member 'third' cannot be resolved without a contextual type
.third : [16, 17, 18, 19, 20, 21, 22, 23],
^
The type checker now has improved diagnostics for result builders, including invalid statements (e.g. invalid return statement), referencing invalid declarations, and pattern matching errors. For example:
import SwiftUI
struct ContentView: View {
@State private var condition = false
var body: some View {
Group {
if condition {
Text("Hello, World!")
.frame(width: 300)
} else {
return Text("Hello, World!")
}
}
}
}
For this code, the type checker will report the following error, along with a Fix-It to remove return
to apply the result builder:
error: cannot use explicit 'return' statement in the body of result builder 'SceneBuilder'
return Text("Hello, World!")
^
Debugging
When debugging Swift code on Apple platforms, variables with resilient types (including Foundation value types such as URL
, URLComponents
, Notification
, IndexPath
, Decimal
, Data
, Date
, Global
, Measurement
, and UUID
) are displayed in the Xcode variable view and the frame variable
/ v
command again.
Leave a Reply