Swift 5.3 is now officially released! 🎉
Swift 5.3 continues to focus on language refinements, the developer experience, and expanding the Swift ecosystem to enable more opportunities to write Swift. These sketch notes, created by Amy Tsai, illustrate the highlights of the Swift 5.3 release:
Full resolution version available on Amy’s tweet
You can also experiment with many of these updates in a playground put together by Paul Hudson.
Table of Contents
Language and Standard Library
New Features and Refinements
Swift 5.3 brings many language refinements that improve the ergonomics of writing Swift code. These updates can help you be a more productive Swift programmer by reducing boilerplate and redundant code, and enabling more functionality to be defined in libraries that you may use.
Swift 5.3 implements the following proposals from the Swift Evolution process:
-
SE-0263 – Add a
String
Initializer with Access to Uninitialized Storage -
SE-0266 – Synthesized
Comparable
conformance forenum
types -
SE-0267 –
where
clauses on contextually generic declarations -
SE-0268 – Refine
didSet
Semantics -
SE-0269 – Increase availability of implicit
self
in@escaping
closures when reference cycles are unlikely to occur -
SE-0276 – Multi-Pattern Catch Clauses
-
SE-0277 – Float16
-
SE-0279 – Multiple Trailing Closures
-
SE-0280 – Enum cases as protocol witnesses
-
SE-0281 –
@main
: Type-Based Program Entry Points -
SE-0282 – Clarify the Swift memory consistency model ⚛︎
-
SE-0285 – Ease the transition to concise magic file strings
-
SE-0286 – Forward-scan matching for trailing closures
Many of these features were proposed and implemented by active community members: Kelvin Ma, Anthony Latsis, Suyash Srijan, Frederick Kellison-Linn and Owen Voorhees. Thank you for your contributions!
Swift 5.3 also includes fixes for several commonly-reported compiler limitations:
-
SR-75 – Unapplied references to protocol requirements are now supported
-
SR-7083 –
lazy
properties can definedidSet
andwillSet
accessors -
SR-8814 – Generic classes can use default implementations of protocol requirements when conforming to protocols with associated types
Runtime Performance Improvements
Swift 5.3 significantly improves both binary code size and runtime memory usage. Measurements of these improvements have yielded exciting results across various projects:
-
Starting with Swift 4, the Swift team at Apple has been measuring the binary code size of a Swift rewrite of a UIKit application (written in Objective-C) that ships with iOS. In Swift 4, the code size was about 2.3x the size of the Objective-C version. In Swift 5.3, the code size is under 1.5x the size of the Objective-C version.
-
In MovieSwiftUI, an excellent open-source SwiftUI app by Thomas Ricouard, the application logic code size is reduced by over 40% compared to Swift 5.1.
-
In a test app that creates an array of 400 model objects, the heap memory due to runtime overhead has been reduced to use less than 1/3 of the heap memory used in Swift 5.1.
These measurements were reported in the ‘What’s New in Swift’ talk at WWDC 2020.
Binary size improvements will vary by patterns of use. The biggest improvement is in projects that declare a large number of types, through reduction in the size of
“value functions” – the invisible functions that the compiler generates to create, copy, and destroy value types. This is especially beneficial to SwiftUI apps.
Additionally, Swift applications now have lower heap memory overhead at runtime. The Swift runtime caches less information on startup to track things like protocol conformances, due to improvements in the runtime that made this caching less necessary. An application written in Swift should now use less heap memory than an otherwise-identical program written in Objective-C.
Developer Experience
Indentation Improvements while Editing Code
The automatic indentation implementation in SourceKit was overhauled in this release, fixing ~50 feedback reports in the process. In particular, the automatic indentation of the following cases are much improved in this release:
-
Chained method calls involving closures
-
Call arguments, parameters, and collection elements that span multiple lines, and
-
Multi-line
if
,guard
andwhile
conditions
Code Completion
Swift 5.3 further improves code completion performance and quality:
-
Repeated code completion invocations inside function bodies are now up to 15 times faster compared to Swift 5.2. This was achieved by reusing some of the computation done for previous completions in the same file. These speedups will be visible in both Xcode and users of SourceKit-LSP.
-
Callable values of user-defined nominal types (SE-0253) are now supported in Swift code completion. Code completion shows the calling signature after a base expression followed by an opening parenthesis
Build Time Improvements
Swift 5.3 incorporates a new strategy for how the compiler handles declarations in your Swift code. These changes bring several concrete improvements:
-
Faster incremental build times by avoiding duplicated compiler work across source files, and more accurately identifying code that has not changed from the previous build
-
Better correctness, by fixing multiple cases where the behavior of the compiler was sensitive to declaration order or nesting
-
Faster compilation of code that uses types with a large number of properties and functions that are imported from another library.
These improvements were achieved by expanding the adoption of a new centralized framework in the compiler that records fine-grained dependency information, caches the results of expensive computation that may need to be repeated, and automatically detects dependency cycles within your Swift code.
Compiler Diagnostics
Swift 5.3 builds upon the diagnostics improvements in Swift 5.2 to further enhance the quality and precision of error messages, especially in SwiftUI code. More specifically, the transition to the New Diagnostics Architecture is now complete in Swift 5.3!
Many of the diagnostics improvements in 5.3 involve complex generic code where a generic argument has a failed requirement, such as a missing conformance. For example, consider the following code:
struct FormList<FieldID> {
init<Data: Collection>(_ data: Data) where Data.Element: Identifiable,
FieldID == Data.Element.ID { ... }
}
struct Field {
let id: String
}
func createForm(fields: [Field]) {
let form = FormList(fields)
}
In Swift 5.2, this compiler reported a very cryptic error message:
error: expression type 'FormList<_>' is ambiguous without more context
let form = FormList(fields)
^~~~~~~~~~~~~~~~
In Swift 5.3, the compiler correctly reports the missing conformance, along with a helpful note showing the source of the requirement:
error: initializer 'init(_:)' requires that 'Field' conform to 'Identifiable'
let form = FormList(fields)
^
note: where 'Data.Element' = 'Field'
init<Data: Collection>(_ data: Data) where Data.Element: Identifiable,
^
Debugging
Swift 5.3 supports better error messages for runtime failures. When debug info is available, the debugger will now display the reason for traps in the standard library instead of just showing an opaque invalid instruction crash.
LLDB is now more robust when debugging binaries that were compiled on a different machine:
-
SDK paths from the build machine are automatically recognized and remapped to local paths.
-
Source and include paths can optionally be remapped with
.dSYM
path remapping dictionaries.
Ecosystem
Swift Package Manager
Resources (SE-0271)
Packages can now contain resources such as images and other data files needed at runtime. Resources are scoped by target, and are processed and embedded into client apps when the package is built. Resources can be accessed from source code using Foundation’s Bundle
API.
Resources that are specific to Apple platforms (such as asset catalogs, storyboards, and CoreData models) can only be built in Xcode, but generic resources are supported on all platforms. New API in the package manifest provides control over which source files to treat as resources.
Localization (SE-0278)
Packages can now contain localizable content such as .strings
files and localized variants of resources. Localizable content can be added to a package using .lproj
directories, and can be accessed using Foundation APIs.
Binary Dependencies (SE-0272)
Packages can now vend prebuilt libraries distributed as XCFrameworks, allowing dependencies on libraries that can’t be distributed as source code. This feature is currently only available when building for Apple platforms. New API in the package manifest lets XCFrameworks be referenced as binary targets.
Conditional Target Dependencies (SE-0273)
A package target’s dependencies can now be declared as conditional, which can be used to limit dependencies by platform. This provides more flexibility to describe complex target dependencies that support multiple platforms.
Note that conditions based on build configuration were also a part of the Swift evolution proposal, but are yet to be implemented, and are therefore not part of Swift 5.3.
Downloads
Official binaries are available for download from Swift.org as toolchains to work with Xcode, as well as Linux toolchains and Docker images. Swift 5.3 is also included in Xcode 12. An official toolchain for Windows will be available in the coming weeks.
Sources
Development on Swift 5.3 was tracked in the release/5.3
branch on the following repositories:
- indexstore-db
- sourcekit-lsp
- swift-tools-support-core
- swift-llbuild
- swift-package-manager
- swift
- swift-cmark
- swift-corelibs-foundation
- swift-corelibs-libdispatch
- swift-corelibs-xctest
- swift-integration-tests
- swift-stress-tester
- swift-syntax
- swift-xcode-playground-support
- llvm-project
The tag swift-5.3-RELEASE
designates the specific revisions in those repositories that make up the final version of Swift 5.3.
The release/5.3
branch will remain open, but under the same release management process, to accumulate changes for the next release.
Leave a Reply