Blog

Breaking changes in Swift 4

31 May, 2017
Xebia Background Header Wave
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 already can work with Swift 4 in the current Xcode 8.3.2.
swift 4 26 5 2017.001 1

Breaking changes

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

swift 4 26 5 2017.001

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 a example.

typealias Name = (firstName: String, lastName: String)
let names: [Name] = [("Bart", "den Hollander")]
I declared a tuple within a 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
    print(last)
})
// 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. This question is answered by Joe Groff, Swift Compiler Engineer at Apple.

I think that although this change may result in better type checker performance, this will lead to worse 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 under water.

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 efficient. An simple example for adding this annotation where foo() is accessible in Objective-C is the following.

class Super {
    @objc
    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 a extension.
In Swift 4, we can now provide the private access level to make it accessible to a extension of the same type. Let’s explain this using examples.

In Swift 3 you could have the following program.

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

The error tells that the private 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 is fixed and languages is accessible via an extension using private. 🎉

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

Current codebase

Would it be possible if I could already check my current codebase against Swift 4 changes? Yes, you could!

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

When the toolchain is changed, you can now 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.

Questions?

Get in touch with us to learn more about the subject and related solutions

Explore related posts