Harry McGovern
Harry McGovern

Reputation: 499

How can I update this Hashable.hashValue to conform to new requirements.?

I'm trying to fix up an old tutorial from RayWenderlich's site, no longer supported. The warning appears in three files, Chain.swift, Cookie.swift and Swap.swift from the "How to Make a Game Like Candy Crush with SpriteKit and Swift:" tutorial

I'm at a loss even after exploring the available replies that appear in many places. I'm struggling to understand just what this code is doing so that I can fix it. I know it's just a warning, and I can probably ignore it, but the game is also showing X where blank tiles should appear so I suspect that it may have something to do with this?

The warning is this:

'Hashable.hashValue' is deprecated as a protocol requirement; conform type 'Chain' to 'Hashable' by implementing 'hash(into:)' instead

File example

  class Chain: Hashable, CustomStringConvertible {
  var cookies: [Cookie] = []
  var score = 0

  enum ChainType: CustomStringConvertible {
    case horizontal
    case vertical

    var description: String {
      switch self {
      case .horizontal: return "Horizontal"
      case .vertical: return "Vertical"
      }
    }
  }

  var chainType: ChainType
  init(chainType: ChainType) {
    self.chainType = chainType
  }

  func add(cookie: Cookie) {
    cookies.append(cookie)
  }

  func firstCookie() -> Cookie {
    return cookies[0]
  }

  func lastCookie() -> Cookie {
    return cookies[cookies.count - 1]
  }

  var length: Int {
    return cookies.count
  }

  var description: String {
    return "type:\(chainType) cookies:\(cookies)"
  }

  var hashValue: Int {
    return cookies.reduce (0) { $0.hashValue ^ $1.hashValue }
  }

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

Upvotes: 2

Views: 2656

Answers (1)

Martin R
Martin R

Reputation: 539815

From the Hashable documentation:

Hashing a value means feeding its essential components into a hash function, represented by the Hasher type. Essential components are those that contribute to the type’s implementation of Equatable. Two instances that are equal must feed the same values to Hasher in hash(into:), in the same order.

And from the hash(into:) documentation:

The components used for hashing must be the same as the components compared in your type’s == operator implementation. Call hasher.combine(_:) with each of these components.

The implementation of

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

shows that cookies is the “essential component” which determines equality of instances. Therefore

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

is a valid (and sensible) implementation of the Hashable requirement.

Upvotes: 6

Related Questions