Breaking changes in Swift 4

In this blog I would like to give insight in the amount of code breaking changes that will be introduced in Swift 4. Also, I will demonstrate how you can already work with Swift 4 in the current Xcode 8.3.2.

Breaking changes

If we summarised all implemented Swift 4 proposals, we would (as of 31–5–17,) come up with the following list.

Implemented proposals in Swift 4

The proposals that are highlighted in bold are proposals that introduce source breaking changes in Swift 4. Let’s dive deeper into each of these proposals.

Distinguish between single-tuple and multiple-argument function types — (SE-0110)

With this proposal, you now have to manually expand tuples from the now-single parameter. Let’s explain using an example.

typealias Name = (firstName: String, lastName: String)
let names: [Name] = [("Bart", "den Hollander")]

I have declared a tuple within an array. Now I want to loop over every tuple in the array and print the last name. Let’s do this in Swift 3.

// Swift 3
names.forEach({ first, last in
print(last) // "den Hollander"

The ‘first’ and ‘last’ variables are expanded from the tuple by the Swift 3 compiler. This is very helpful and readable.
Now let’s do the same within Swift 4.

// Swift 4
names.forEach({ first, last in
// error: closure tuple parameter '(firstName: String, lastName: String)' does not support destructuring

The reason this doesn’t work anymore is because in Swift 4 you have to manually expand tuples from a single parameter. You can do the following to fix this.

// Swift 4
A: Expand by providing the tuple key
names.forEach({ name in
print(name.lastName) // "den Hollander"
B: Expand by providing the amount of tuple elements in a variable
names.forEach({ name in
let (first, last) = name
print(last) // "den Hollander"
C: Change to a for loop
for (first, last) in names {
print(last) // "den Hollander"

Still the question is raised as to why this change was introduced. Joe Groff, Swift Compiler Engineer at Apple, answered this question.

Joe Groff about SE-0110

I think that although this change may result in better type checker performance, this will lead to decreased readability of the syntax.

Limiting @objc inference — (SE-0160)

In Swift 3, the rule of thumb with the @objc annotation was the following.

To be accessible and usable in Objective-C, a Swift class must be a descendant of an Objective-C class or it must be marked @objc.

This means that you would have to comply your Swift class to NSObject and every property of that class would than be annotated with @objc for you by the Swift 3 compiler. The same applies when using #selector in Swift because they work with Objective-C behind the scenes.

With this proposal you now have to manually annotate every Swift class property that is used in Objective-C with @objc so the compiler can work more efficiently. An simple example for adding this annotation where foo() is accessible in Objective-C is the following.

class Super {
func foo() { }

Note: A migration plan is provided in this proposal. This plan gives a 3 step workflow that can help in some projects.

Improve Interaction Between private Declarations and Extensions — (SE-0169)

SE-0169 changes the access control rules once again. This time the access control rules are changed for private and fileprivate in combination with using an extension.
In Swift 4, we can now provide the private access level to make it accessible to an extension of the same type. Let’s explain this using a example.

In Swift 3 you could have the following program.

struct Netherlands {
private var languages = ["Dutch"]
extension Netherlands {
mutating func add(language: String) {
// error: 'languages' is inaccessible due to 'private' protection level

The error tells that theprivate access level withholds the extension from accessing languages. This is strange because you create a extension for the same type so you should be possible to access languages.

In Swift 4 this has been fixed and languages is accessible via an extension using private 🎉.

The breaking change in this proposal accures when there are private properties with the same signature in same type/extension but in different scopes. An Invalid redeclaration of 'signatureX' error would then follow. Changing the signature would resolve this issue.

Check current codebase

Would it be possible to check my current codebase against Swift 4 changes? Yes, you can!

You only need to download and install the latest Swift 4.0 snapshot and select the installed snapshot in the toolchain menu in Xcode. The following image shows where the toolchain menu is located.

Toolchain in Xcode
Select toolchain in Xcode

When the toolchain has been changed, you can start your project and try to build it with the snapshot!

A snapshot is of course not the final version, but there are already a lot of proposals implemented of which you can create a rough estimate of the amount of work that comes ahead of you. Doing so, you know what the impact of this new Swift version will be on your existing code base.

Thanks for reading!

Follow me on twitter to get updated about new blogs.

Originally published at