How To Get Equatable And Hashable For Free

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 or Hashable cannot be automatically synthesized in an extension.

    Xcode error message: Equatable 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 or Hashable.

Further Reading