1

With Xcode 10, and Swift 4.2 there are additional types that conform to Hashable as long as their elements also conform to Hashable (Array, Dictionary, etc).

I currently have some code in my project to add Hashable conformance for Swift 4.1 and below like this:

extension Array: Hashable where Element: Hashable {
  public var hashValue: Int {
    let prime = 31
    var result = 1
    for element in self {
      result = prime * result + element.hashValue
    }
    return result
  }
}

However, even if I add #if !swift(>=4.2) around the code I still see the same warning in Xcode.

Xcode 10 Hashable Warning

My question is, how can I keep the conditional conformance to Hashable for Swift 4.1 and below, but silence the warning for Swift 4.2?

Steven Hepting
  • 12,394
  • 8
  • 40
  • 50

1 Answers1

3

The conditional compilation statement #if swift(...) checks against the language version you're running with – which can differ from the compiler (and therefore standard library) version.

In your case, it sounds like you're using a Swift 4.2 compiler in Swift 4 compatibility mode, which gives you a language version of 4.1.50. This therefore passes the conditional compilation statement and your extension is compiled, giving you a duplicate conformance.

In order to check for a compiler version less than 4.2, you want the following:

// less than 4.2 in Swift 4 compat mode and (less than 4.2 in 3 compat mode or
// greater than 4).
#if !swift(>=4.1.50) && (!swift(>=3.4) || swift(>=4.0))
extension Array : Hashable where Element : Hashable {
  public var hashValue: Int {
    let prime = 31
    var result = 1
    for element in self {
      result = prime * result + element.hashValue
    }
    return result
  }
}
#endif

Things will be much better with the new #if compiler directive, which is available in Swift 4.2 from Xcode 10 beta 4 onwards (confirmed by @MartinR). With that, you can directly test for the compiler version, ignoring any compatibility modes it might be running in.

This doesn't help your specific case as you need the code to be understood by both Swift 4.2 and 4.1 compilers (as also pointed out by Martin), but for future compatibility problems, you could for example use #if !compiler(>=5) in order to only compile a block of code if using a 4.2 compiler.

Hamish
  • 78,605
  • 19
  • 187
  • 280