Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid Equatable and Hashable boilerplate, Swift 4.2

On project we are using classes for model's layer and because of that I have to write code like this:

// MARK: - Hashable
extension Player: Hashable {
    static func == (lhs: Player, rhs: Player) -> Bool {
        return lhs.hashValue == rhs.hashValue
    }

    func hash(into hasher: inout Hasher) {
        hasher.combine(self.name)
    }
}

Can this boilerplate can be somehow avoided? Is it possible to implement that Equatable compare by .hashValue by default? Thanks.

like image 731
Bohdan Savych Avatar asked Nov 22 '25 10:11

Bohdan Savych


1 Answers

This is wrong, and it would make no sense that the compiler synthesizes it automatically:

static func == (lhs: Player, rhs: Player) -> Bool {
    return lhs.hashValue == rhs.hashValue
}

Identical objects must have the same hash value, but not the other way around: Distinct objects can have the same hash value.

Concretely, in your example: The name is a string and there are infinitely many different strings, but only 264 different hash values. So there must be two different strings with the same hash value.

If all stored properties are Hashable then the compiler can synthesize the conformance for you completely. For example

struct Player : Equatable, Hashable {
    let name: String
    var score: Int
}

Here two players are “identical” if they have the same name and the same score.

If there are non-hashable properties, or if you want to customize the concept of identity then you have to override == and hash(into) accordingly. The hash function should use the same properties which determine the identity in ==. For example

struct Player : Equatable, Hashable {
    let name: String
    var score: Int

    static func == (lhs: Player, rhs: Player) -> Bool {
        return lhs.name == rhs.name
    }

    func hash(into hasher: inout Hasher) {
        hasher.combine(self.name)
    }
}

Now two players are “identical” if they have the same name.

like image 96
Martin R Avatar answered Nov 24 '25 04:11

Martin R