Swift 4.1 is available with Xcode 9.3 and brings a nice gift. The compiler can now automatically generate the code to make your types Equatable
or Hashable
. This only applies to structs and enums (not classes) and there are conditions but this can still save you from a lot of boring boilerplate code.
Last updated: May 9, 2021
Automatic Synthesis Of Equatable
For a recap of how and when to make your types equatable see this earlier post. In that example I had a struct representing a country with two String
properties and a Bool
:
struct Country {
let name: String
let capital: String
var visited: Bool
}
To make this type Equatable
meant adopting the protocol and implementing the static ==
operator for the type. I did that in an extension:
extension Country: Equatable {
static func == (lhs: Country, rhs: Country) -> Bool {
return lhs.name == rhs.name &&
lhs.capital == rhs.capital &&
lhs.visited == rhs.visited
}
}
Now with Swift 4.1 you can remove the boilerplate extension code. You only need to tell the compiler that you want this type to be Equatable
by declaring conformance to the protocol:
struct Country: Equatable {
let name: String
let capital: String
var visited: Bool
}
That’s it! The compiler will do the rest.
let france = Country(name: "France", capital: "Paris", visited: true)
let spain = Country(name: "Spain", capital: "Madrid", visited: true)
if france == spain { ... } // false
Automatic Synthesis Of Hashable
For a recap of how and when to make your types hashable see this earlier post. A common reason is to store them in a Set
or Dictionary
.
To manually make my Country
type hashable I needed to implement the hashValue
property:
extension Country: Hashable {
var hashValue: Int {
return name.hashValue ^ capital.hashValue ^ visited.hashValue
}
}
Starting with Swift 4.1 we can delete this boilerplate and let the compiler do the work. Automated synthesis of Hashable
works much like Equatable
. Declare conformance in the type declaration and your type gets a hashValue
:
struct Country: Hashable {
let name: String
let capital: String
var visited: Bool
}
let uk = Country(name: "United Kingdom", capital: "London", visited: true)
let france = Country(name: "France", capital: "Paris", visited: true)
// Countries added to a dictionary
let counts = [uk: 1000, france: 2000]
counts[uk] // 1000
Since Hashable
inherits from Equatable
you do not need to include the Equatable
declaration in this case.
Some Conditions Apply
Always read the small print…
-
You can override the automatic implementation by providing your own implementation (as before).
-
You cannot put the protocol conformance in an extension it must be part of the original type declaration. If you try you will get a compiler warning that
Equatable
orHashable
cannot be automatically synthesized in an extension.Either add your own implementation in the extension or move the protocol conformance to the original declaration.
-
It only works for structs or enums (not classes) and then only when each stored property of a struct or associated value of an enum is itself
Equatable
orHashable
.