UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

I tried SE-0185 and it’s a thing of beauty

A Google engineer is working to remove more drudgery from Swift.

Paul Hudson       @twostraws

Even though Swift is for the most part a clean, modern language (let’s just pretend @objc doesn’t exist, OK?) it still has a few areas that are unnecessarily clunky.

For example, before Swift 4 came along it used to be mind-numbingly dull making your data types conform to NSCoding – it always meant writing near-identical boilerplate code to read and write all the properties you wanted to store.

Thanks to Swift 4’s Codable protocol that pain point has gone away, but work is underway to solve another annoyance: the need to write functions to make trivial data types conform to Equatable and Hashable.

To demonstrate the problem, consider this struct:

struct Person: {
    var firstName: String
    var lastName: String
    var age: Int
    var city: String
    var likesSinging: Bool
}

There’s nothing fancy there – a few strings, an integer, and a boolean. If we wanted to create a couple of instances of those structs, Swift provides us with a memberwise initializer so we can write code like this:

let taylor = Person(firstName: "Taylor", lastName: "Swift", age: 27, city: "Nashville", likesSinging: true)
let notTaylor = Person(firstName: "Taylor", lastName: "Swift", age: 27, city: "London", likesSinging: true)

The problem comes if we want to compare those two instances. They are almost the same, but not quite: one lives in London and the other in Nashville.

If we wanted to compare the two values to make sure they were different we would need to make Person conform to the Equatable protocol. In practice that means implementing the == function so that it returns true if two values match, which usually goes something like this:

struct Person: Equatable { 
    var firstName: String
    var lastName: String
    var age: Int
    var city: String
    var likesSinging: Bool

    static func ==(lhs: Person, rhs: Person) -> Bool {
        return lhs.firstName == rhs.firstName
            && lhs.lastName == rhs.lastName
            && lhs.age == rhs.age
            && OH GOD I'VE LOST THE WILL TO LIVE
    }
}

Like I said: drudgery.

Well, there’s some good news: Tony Allevato from Google wrote a Swift proposal called SE-0185: Synthesizing Equatable and Hashable conformance, and it proposes exactly what its name suggests – if it’s possible for the compiler to automatically generate a complete implementation of the Hashable and Equatable protocols, then allow the user to opt into it.

Even better, Allevato submitted a large pull request that implemented his proposal in full, and it’s already undergoing review by the rest of the Swift team.

I was keen to see if SE-0185 lived up to my hopes, so I cloned Allevato’s Swift fork, activated his synthesize-equatable-hashable branch, then compiled Swift based on that branch.

The result? Well, it’s almost magic, quite frankly. With his change in place, we can make our Person struct conform to Equatable like this:

struct Person: Equatable {
    var firstName: String
    var lastName: String
    var age: Int
    var city: String
    var favoriteColor: String
}

Yes – all you need to do is add : Equatable, and after that the compiler takes care of the rest.

As you can see, this change is opt in – you need to state that your data type conforms to Equatable otherwise the compiler won’t synthesize the appropriate functions. This means by default no extra code will get added to your app unless you actually request it, which is a sensible move.

Of course, you’re a smart Swift developer, so you watched Doug Gregor’s Building Better Apps with Value Types in Swift talk at WWDC 15, where he emphasized the importance of Equatable:

When you're building a value type, it's extremely important that it conform to the Equatable protocol. Because every value type out there should be equatable. That means it has the == operator to do a comparison, but that operator has to behave in a sensible way.

Well, with SE-0185 you get to have all the benefits of Equatable (and Hashable too!), without having to go through all the grunt work – a huge improvement and a win all around. And if you decide you want a custom equality check, you can go ahead and write it because any user-defined == function will automatically override what the compiler would have generated.

Allevato’s pull request implementing SE-0185 remains in active review by the Swift team, but I’m hopeful it will be ready in time for Swift 4.1. Regardless of when it finally ships, I’m looking forward to ripping out hundreds if not thousands of lines of boilerplate Equatable and Hashable code and thinking about it rarely if ever again.

Hacking with Swift is sponsored by RevenueCat

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

BUY OUR BOOKS
Buy Pro Swift Buy Pro SwiftUI Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let us know!

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.