I can write global functions to evaluate hashValues, e.g.:
func hashValueHashable<T: Hashable>(h: T) -> Int { // Pointless because of static dispatching!
return h.hashValue
}
func hashValueNonHashable(a: Any) -> Int {
if let a = a as? AnyObject {
return ObjectIdentifier(a).hashValue
}
return 0
}But this isn't very satisfactory because I need to manually specify which version, i.e. no dynamic dispatch.
Therefore I tried to work out how to do something similar using extensions. My 1st try was extending `Any`:
extension Any: Hashable { // Error: Non-nominal type `Any` cannot be extended
var hashValue: Int {
if let self = self as AnyObject {
return ObjectIdentifier(self).hashValue
}
return 0
}
}No luck. How about `AnyObject`?
extension AnyObject: Hashable { // Error: `AnyObject` protocol cannot be extended
var hashValue: Int {
return ObjectIdentifier(self).hashValue
}
}No luck again. How about `Hashable`?
extension Hashable where Self: AnyObject {
var hashValue: Int {
return ObjectIdentifier(self).hashValue
}
}
func ==<T: AnyObject>(lhs: T, rhs: T) -> Bool {
return lhs === rhs
}Works 🙂. Note you need `==` also because `Hasable` extends `Equatable`.
This is not as convenient to use as extending `Any` or `AnyObject` because you have to add `Hashable` to types which as shown above you can't do to `Any` nor `AnyObject`. Therefore nothing you can do for values or final classes since you can't inherit from them; but non-final classes can be extended or inherited from to add `Hashable` and classes that you write can implement `Hashable`, e.g.:
class AnObject: Hashable {}
func test(lhs: AnObject, _ rhs: AnObject) {
print((lhs == rhs) == (lhs.hashValue == rhs.hashValue))
}
let a = AnObject()
let b = AnObject()
let c = AnObject()
let a1 = a
let a2 = a1
test(a, a)
test(a, b)
test(b, c)
test(c, a)
test(b, a)
test(a, a1)
test(a1, a2)
test(a2, a)All tests print true.
Any suggestions of how this might be improved? In particular, directly extending `Any` or `AnyObject`.