What’s New in Swift 5.2
Swift 5.2 is now available as part of Xcode 11.4. In this article, you’ll get an overview of the changes you’ll see moving to Swift 5.2. By Bill Morefield.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
What’s New in Swift 5.2
20 mins
- Improved Diagnostics and Error Messages
- Easier Troubleshooting
- Not Just SwiftUI
- Syntactic Sugar Additions
- Calling Types as Functions
- Cleaner Syntax
- Machine Learning Application
- Key Path Expressions as Functions
- Subscripts With Default Arguments
- Major Bug Fixes
- Lazy Filters are Called in Order
- Default Values From Outer Scopes
- Warning When Passing Dangling Pointers
- Overridden Methods Can’t Use Incorrect Generics
- Class-Constrained Protocol Extensions
- Disambiguate Functions with Named Parameters
- Where to Go From Here
Swift 5.2 is now available as part of Xcode 11.4. This article presents an overview of the changes you’ll see in this latest version.
Overall, Swift 5.2 is a minor release which is not necessarily a bad thing. It does bring many tweaks and minor improvements that will help the workflow of Swift developers. In this release, you’ll find:
- Better diagnostics with more helpful error messaging, especially for SwiftUI.
- New features that will simplify certain tasks.
- Major bug fixes.
In many of the sections below, you’ll see references to the Swift Evolution proposals, like SE-0253, or the Swift bug reports, like SR-11298. You can explore these in greater depth using the links provided.
Also, follow along with the Playgrounds created for this article. Use the Download Materials button at the top or bottom to download them.
To start, you’ll explore the highest-profile feature: improvements to the error messages.
Improved Diagnostics and Error Messages
Do you always write perfect code on the first try? If not, you’ll love the improvements to the diagnostics engine in Swift 5.2! When you have an error in your code, the compiler gives you a more accurate description of the error and its location.
To be fair, the Swift compiler already did a good job reporting most errors in your code. The code below:
var str = "10"
let total = str + 5
…produced a clear error message:
The error message told you that you cannot use the ‘+’ operator to join a String
and an Int
. Depending on your intent, it also pointed you toward the action to fix the problem. If the goal was to add 5 to the number represented by the string, then you could fix the error like this:
var str = "10"
let total = Double(str)! + 5
At other times, however, the error messages weren’t all that helpful. This was especially true with errors related to type checking. Swift 5.2 addressed this issue by focusing on improvements to the type checker.
Easier Troubleshooting
Consider the following code for SwiftUI:
struct SquareView : View {
@State var angle = 0.0
var body: some View {
VStack {
TextField("Angle:", text: $angle)
Rectangle()
.rotation(Angle(degrees: angle))
.frame(width: 100.0, height: 100.0)
}
}
}
Prior to Xcode 11.4, the error message you would have seen was this:
Not very helpful, eh? It was common to see unclear error messages such as this when working with SwiftUI. This made it that much harder to learn to use SwiftUI. Finding even the simplest typos became a process of tediously re-reading, removing or commenting out code to isolate the actual error.
Look again at the code block. Can you spot the actual problem? As a hint, it has nothing to do with converting a Double
to a CGFloat
!
Now open swiftui.playground in the starter folder. You’ll see that the compiler gives you a much more useful and actionable error message:
The error message points you to the correct line with the error and tells you the problem: You’re passing a binding to Double
to a method that expects a binding to String
.
Now that you know what to do to fix this error, replace the line indicated with this:
TextField("Angle", value: $angle, formatter: NumberFormatter.decimalFormatter)
Not Just SwiftUI
While you’ll notice better error messaging most often in SwiftUI, you’ll also see improvements in other Swift code. Open swift52.playground in the final project and you’ll find this code commented out:
let x: [Int] = [1, 2, 3, 4]
let w: UInt = 4
let filtered = x.filter { ($0 + w) > 42 }
This code attempts to add an Int
to a UInt
without a cast and will not compile. Prior to Swift 5.2, the compiler displayed the following error:
error: binary operator '+' cannot be applied to operands of type 'Int' and 'UInt'
Now uncomment the code and you’ll see a more precise and helpful error message:
error: new-features.playground:34:22: error: cannot convert value of type 'UInt' to expected argument type 'Int'
_ = x.filter { ($0 + y) > 42 }
^
Int( )
Syntactic Sugar Additions
Swift already has quite a bit of syntactic sugar built into the language. Swift 5.2 adds to this by bringing two new features that certain developers will find very handy: Calling types as functions and using key path expressions as functions.
Calling Types as Functions
This new feature introduces statically callable values to Swift. But what does that mean? Well, it means that you can call classes or other structures as if they were functions.
To implement this feature in your code, you add a method named callAsFunction(_:)
to the type. That’s it! There’s no step two.
With this addition, you can now call the value as a function. For example, take this type that represents a quadratic equation — a common mathematical function in the form of ax^2 + bx + c:
struct Quadratic {
var a: Double
var b: Double
var c: Double
func callAsFunction(_ x: Double) -> Double {
a * pow(x, 2) + b * x + c
}
}
You define your type as with any other value:
let f = Quadratic(a: 4, b: 4, c: 3)
Note that adding callAsFunction(_:)
doesn’t prevent you from using the default init()
method.
The choice of a mathematical type for this example is not a coincidence. Using syntax similar to mathematical notation provides the primary motivation for this feature.
let y = f(5)
As with any method, you can have multiple overrides for callAsFunction(_:)
in your type. If you wanted to also calculate values for an array of Double
s and return the result as a new array, you could add a second implementation of callAsFunction(_:)
like this:
func callAsFunction(_ xs: [Double]) -> [Double] {
xs.map { callAsFunction($0) }
}
This code takes an array of Double
s and uses map()
and the previous implementation of callAsFunction(_:)
to produce an array with the results. Swift determines the appropriate method to call as it would for any other overridden function.
let z = f([5, 7, 9])