What's New in Swift 5.8

⋅ 7 min read ⋅ Swift Swift 5.8

Table of Contents

Swift 5.8, which was released along with Xcode 14.3, brings a lot of improvement to the Swift language.

In this article, I will highlight one that I find interesting.

I categorize features into three groups.

Preparing for Swift 6:

Better support for future features:

Other improvements:

Preparing for Swift 6

I think one of the big themes of this version is preparing everyone for Swift 6.

Swift 6 contains a lot of improvements that might have a source-compatibility impact and could not be enabled by default since it will break semantic versioning.

But some of those improvements are already implemented in Swift compiler behind the scene.

Swift 5.8 allows us to opt-in for those features, which will smooth out the transition period.

Swift accomplished this using Feature Flag and SE-0362: Piecemeal adoption of upcoming language improvements.

Feature Flag

Now, every breaking Swift feature will contain an "Upcoming feature flag" field, which includes the feature's name.

We will use this to enable that feature in our code.

You will see this field in some of the new Swift 5.8 features.

Concise magic file names
Concise magic file names

But old features that aim for Swift 6.0 also got this flag.

Regex Literals
Regex Literals

Incrementally adopt Swift 6

SE-0362: Piecemeal adoption of upcoming language improvements bring a way to enable new features that put behind the feature flag.

To enable a feature X, we add -enable-upcoming-feature X to Other Swift Flags in Xcode.

Other Swift Flags.
Other Swift Flags.

You can easily support sarunw.com by checking out this sponsor.

Sponsor sarunw.com and reach thousands of iOS developers.

Better support for future features

As Swift evolved, it introduced many new features to the language.

In the past, there was not much standard for handling new language features.

Swift 5.8 try to improve this with Conditional compilation for attributes and Function back deployment.

Conditional compilation for attributes

As Swift evolved, it introduced many new attributes to the language, e.g., @preconcurrency introduced in Swift 5.6 (SE-0337).

However, adopting these new attributes means the source code won't compile with an older compiler that doesn't recognize the new attributes.

Before Swift 5.8, we had to use conditional compilation to compile code based on the compiler version.

#if compiler(>=5.6)
@preconcurrency
protocol P: Sendable {
func f()
func g()
}
#else
protocol P: Sendable {
func f()
func g()
}
#endif

There are two problems with this approach.

  1. Code duplication since we have to repeat the code multiple times.
  2. Checking for compiler version for attributes is error-prone.

Swift 5.8 introduced SE-0367: Conditional compilation for attributes, which allows us to check the availability of Swift attributes.

#if hasAttribute(AttributeName)

As a result, we can make the code less repetitive and more concise.

#if hasAttribute(preconcurrency)
@preconcurrency
#endif
protocol P: Sendable {
func f()
func g()
}

Function back deployment

SE-0337: Function Back Deployment add a new @backDeployed attribute that allows Library or Framework author to backport new APIs to be used on the old deployment target.

As an example, the badge modifier was introduced in iOS 15. SwiftUI team can make it available for older versions of iOS using the @backDeployed attribute like this.

extension View {
@available(iOS 13.0, *)
@backDeployed(before: iOS 15.0)
public func badge(_ count: Int) -> some View {
self.overlay(Text("Fake Badge"))
}
}

You can easily support sarunw.com by checking out this sponsor.

Sponsor sarunw.com and reach thousands of iOS developers.

Other improvements

New #file behavior

SE-0274: Concise magic file names change behavior of #file.

#file will return the file name and the module in which it appears. And not including any path in it.

// Before Swift 5.8
print(#file)
// /Users/sarunw/Documents/MyProject/MyProject/ContentView.swift

// Swift 5.8
print(#file)
// MyProject/ContentView.swift

Allow implicit self for weak self captures

SE-0365: Allow implicit self for weak self captures, after self is unwrapped allows us to omit a self keyword for weak self that has been unwrapped.

This change reduces visual noise and maintains consistency with SE-0269: Increase availability of implicit self in @escaping closures when reference cycles are unlikely to occur in Swift 5.3.

Before Swift 5.8

class ViewController: UIViewController {
var button: UIButton!

func setup() {
button.addAction(
UIAction { [weak self] _ in
guard let self else { return }

self.didTapButton()
},
for: .touchUpInside)
}

func didTapButton() {}
}

Swift 5.8

class ViewController: UIViewController {
var button: UIButton!

func setup() {
button.addAction(
UIAction { [weak self] _ in
guard let self else { return }

didTapButton()
},
for: .touchUpInside)
}

func didTapButton() {}
}

Better print for AnyKeyPath

SE-0369: Add CustomDebugStringConvertible conformance to AnyKeyPath improve an information return when printing out a keypath object.

Before Swift 5.8

struct User {
let firstName: String
let lastName: String
var nickName: String
}

print(\User.firstName)
// Swift.KeyPath<ModuleName.User, Swift.String>

print(\User.lastName)
// Swift.KeyPath<ModuleName.User, Swift.String>

print(\User.nickName)
// Swift.WritableKeyPath<ModuleName.User, Swift.String>

After Swift 5.8

print(\User.firstName)
// \User.firstName

print(\User.lastName)
// \User.lastName

print(\User.nickName)
// \User.nickName

Document sorting as stable

Swift's sorting algorithm was changed to be stable before Swift 5, but the documentation didn't reflect this fact.

SE-0372: Document Sorting as Stable update the documentation to align with the implementation detail.

Update documentation.
Update documentation.

A stable sort is a sort that keeps the original relative order for any elements that compare as equal.

var roster = [
Player(first: "Sam", last: "Coffey"),
Player(first: "Ashley", last: "Hatch"),
Player(first: "Kristie", last: "Mewis"),
Player(first: "Ashley", last: "Sanchez"),
Player(first: "Sophia", last: "Smith"),
]

roster.sort(by: { $0.first < $1.first })
// roster == [
// Player(first: "Ashley", last: "Hatch"),
// Player(first: "Ashley", last: "Sanchez"),
// Player(first: "Kristie", last: "Mewis"),
// Player(first: "Sam", last: "Coffey"),
// Player(first: "Sophia", last: "Smith"),
// ]

In this case, "Ashley Hatch" and "Ashley Sanchez" are compared as equal.

With stable sort, "Ashley Hatch" and "Ashley Sanchez" relative position remains the same ("Ashley Hatch" comes before "Ashley Sanchez").

Remove all limitations on variables in result builders

Before Swift 5.8, view builders had many limitations around declaring a local variable.

SE-0373: Lift all limitations on variables in result builders remove all of those limitations.

So, you can declare a local variable the way you want.

The following example is a valid declaration in Swift 5.8.

struct FooViewBuilder: View {
var body: some View {
var computedVar: String {
return "Computed"
}
lazy var lazyVar = compute()
let uninitializedVar: String
let defaultNilVar: String?
@AppStorage("example_string") var propertyWrapperVar = "Foo"

VStack {
Text("Foo")
}
}

func compute() -> String {
return "Foo"
}
}

There are still some updates that I didn't cover in this article. You can see all the updates in Swift 5.8 in the Swift Evolution.


Read more article about Swift, Swift 5.8, or see all available topic

Enjoy the read?

If you enjoy this article, you can subscribe to the weekly newsletter.
Every Friday, you'll get a quick recap of all articles and tips posted on this site. No strings attached. Unsubscribe anytime.

Feel free to follow me on Twitter and ask your questions related to this post. Thanks for reading and see you next time.

If you enjoy my writing, please check out my Patreon https://www.patreon.com/sarunw and become my supporter. Sharing the article is also greatly appreciated.

Become a patron Buy me a coffee Tweet Share
Previous
How to Hide Navigation Bar on Tap in UIKit

Since iOS 8, we can easily add a tap gesture to show and hide a navigation bar and toolbar. Let's learn why and how to do it.

Next
How to Open using Rosetta in Xcode 14.3

If you are using Xcode 14.3 or later, you might notice that the option to open Xcode in Rosetta is no longer available. Let's find out what changes.

← Home