9

Reduce boilerplate code with an automatic synthesis of Equatable and Hashable co...

 3 years ago
source link: https://sarunw.com/posts/reduce-boilerplate-code-with-automatic-synthesis-of-equatable-and-hashable-conformance/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Reduce boilerplate code with an automatic synthesis of Equatable and Hashable conformance


Table of Contents

Equatable and Hashable are two essential protocols in the Swift world. Today, you will learn an old Swift feature that is very helpful if you want to make your types conform to those protocols.

Equatable

Equatable make your types can be compared for value equality.

In the past, you have to do all of this manually.

struct Person {
let firstName: String
let lastName: String
}

If you want to compare two Person, you have to conform Equatable and write an implementation detail yourself.

extension Person: Equatable {
static func == (lhs: Person, rhs: Person) -> Bool {
return
lhs.firstName == rhs.firstName &&
lhs.lastName == rhs.lastName
}
}

This might seem like a trivial task, but most of your models are struct, which should be able to test for equality like other value types. That means you have to do it repeatedly for all of your models, which is a tiring process and error-prone.

Automatic Synthesis Of Equatable

In Swift 4.1, you can remove the boilerplate entirely. You only need to tell the compiler that you want to opt-in for Equatable by declaring the protocol's conformance.

So, this is all you need to do to make your custom type conform Equatable.

struct Person: Equtable {
let firstName: String
let lastName: String
}

// Or

struct Person {
let firstName: String
let lastName: String
}

extension Person: Equatable {}

sponsor-codeshot.png

Hashable

Hashable makes your types can be hashed to produce an integer value, which is required if you want your type to be used as a key in Dictionary or add to a Set.

To make our Person struct support Hashable, we can manually do it like this.

extension Person: Hashable {
func hash(into hasher: inout Hasher) {
hasher.combine(firstName)
hasher.combine(lastName)
}
}

Automatic Synthesis Of Hashable

Just like Equatable, Swift 4.1 automatically synthesize conformance to Hashable.

You can opt-in for this by declaring the conformance to the protocol. Since Hashable is a inherits from Equatable, you also get synthesis for Equatable for free.

struct Person: Hashable {
let firstName: String
let lastName: String
}

// Or

struct Person {
let firstName: String
let lastName: String
}

extension Person: Hashable {}

Limitations and conditions

There are some limitations and conditions that you should know.

Overriding synthesized conformances

If you have don't want to compare every property in your type, You can provide implementations of == or func hash(into: inout Hasher) and that will override the one that generated by the compiler.

Conditions where synthesis is allowed

For a struct, it only works if all of its stored instance properties conform to Equatable or Hashable.

For an enum with an associated value, it only works if all of its cases conform to Equatable or Hashable.

For an enum with no associated values, Swift already derives Equatable and Hashable conformance for them without opting in.

I find this automatic synthesis of Equatable and Hashable is particularly useful for an enum.

The code that must be written to implement equality for enums is quite verbose and very error-prone. If you add a new enum case and forget to add a counterpart == case, the bug is waiting for you there.

enum Token: Equatable {
case string(String)
case number(Int)
case lparen
case rparen

static func == (lhs: Token, rhs: Token) -> Bool {
switch (lhs, rhs) {
case (.string(let lhsString), .string(let rhsString)):
return lhsString == rhsString
case (.number(let lhsNumber), .number(let rhsNumber)):
return lhsNumber == rhsNumber
case (.lparen, .lparen), (.rparen, .rparen):
return true
default:
return false
}
}
}

With automatic synthesis, you can save yourself from all the headaches and reduce the code to this.

enum Token: Equatable {
case string(String)
case number(Int)
case lparen
case rparen
}

Synthesis for class types and tuples

Synthesize conformances for class, and tuples are not supported.

sponsor-codeshot.png

Conclusion

Things move quickly in the iOS development world. Each year you have a lot of stuff to cache up, and it is ok to miss some of them. Today, I introduced you to a handy Swift feature that I don't aware of (I knew it and forgot about its existence), and it introduced way back in Swift 4.1 on March 29, 2018.

Related Resource


You may also like

What is @discardableResult

Learn about this Swift attribute and its purpose.

Swift
How to use UIKit in SwiftUI

Using UIView and UIViewController in SwiftUI

Swift
Sign in with Apple Tutorial, Part 3: Backend – Token verification

Part 3 in a series Sign in with Apple. In this part, we will see how backend can use the token to sign up/sign in users.

Swift

Read more article about Swift, Swift 4.1, Equtable, Hashable,

or see all available topic

Get new posts weekly

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 — entirely for free.

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

Tweet

Share

Previous
Setting default values for NSUserDefaults

NSUserDefaults is a go-to database for saving users' preferences. Learn how to populate it with your default values.

Next
Better print debugging with Xcode breakpoints

Print debugging is the simplest form of debugging technique, but it possesses some drawbacks. Let's see how we can make it better by using Xcode breakpoints.

← Home


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK