Unfortunately, as of Swift 4.2 the standard library still doesn't provide conditional conformance to Hashable
for tuples and this is not considered valid code by the compiler:
extension (T1, T2): Hashable where T1: Hashable, T2: Hashable {
// potential generic `Hashable` implementation here..
}
In addition, structs, classes and enums having tuples as their fields won't get Hashable
automatically synthesized.
While other answers suggested using arrays instead of tuples, this would cause inefficiencies. A tuple is a very simple structure that can be easily optimized due to the fact that the number and types of elements is known at compile-time. An Array
instance almost always preallocates more contiguous memory to accommodate for potential elements to be added. Besides, using Array
type forces you to either make item types the same or to use type erasure. That is, if you don't care about inefficiency (Int, Int)
could be stored in [Int]
, but (String, Int)
would need something like [Any]
.
The workaround that I found relies on the fact that Hashable
does synthesize automatically for fields stored separately, so this code works even without manually adding Hashable
and Equatable
implementations like in Marek Gregor's answer:
struct Pair<T: Hashable, U: Hashable>: Hashable {
let first: T
let second: U
}
(x:Int,y:Int)
is not a Hashable thing :) – Janikhash(x) ^ hash(y)
. – WronglyHashable
, which is required for the key portion of the SwiftDictionary
. I should have surrounded in code block, sorry :) – JanikHashable
. – Janikhashable
) is because they are not strictly immutable. If you define it usinglet
, it is immutable, but if you define it usingvar
, it is not. The hash used as a key in a dictionary MUST be immutable by the definition of a hash table, and as any kind of reasonable hash would directly depend on the values inside a container, a mutable container cannot be hashed (and likewise, an immutable container containing mutable objects cannot be reasonably hashed). – EchinodermHashable
, but as any reasonable hash is value-dependent, you're just asking for undefined behavior by working around the system this way, unless you make your container immutable. – EchinodermHashable
and can't be extended to do so. Tuples are no more mutable than strings orInt
s, which are just fine as Dictionary keys. – Cush