[swift-users] Set-uniqueness of instances with distinct hashValue

Rien Rien at Balancingrock.nl
Sun Oct 23 04:19:14 CDT 2016


If you change the “==“ function to:

func == (lhs: X, rhs: X) -> Bool {
    return (lhs.x == rhs.x) && (lhs.hashValue == rhs.hashValue)
}

then the example works as expected.

Apple says this: “A hash value, provided by a type’s hashValue property, is an integer that is the same for any two instances that compare equally.”

You violated this rule in the original example.

Apple says: “Set and dictionary performance depends on hash values that minimize collisions for their associated element and key types, respectively.”

From which I draw the conclusion that there are “under the hood” optimizations at work that produce the results in your example. These can probably change from compiler version to compiler version and are principally unreliable because your example violated the rule for Hashable.

Rien.

> On 23 Oct 2016, at 10:51, milos via swift-users <swift-users at swift.org> wrote:
> 
> Given an array of instances of a `Hashable` value type, all equal according to `Equatable` protocol, but with distinct `hashValue`s, I would expect that initialising a set with that array would preserve all the instances. Instead, running the code below in an iOS playground on Xcode 8.0 (8A218a), results in a behaviour that I cannot explain. If anyone can, I’d be very grateful!
> 
>    struct X: Hashable {
>        let x: Int
>        let hashValue: Int
> 
>        static func == (lhs: X, rhs: X) -> Bool {
>            return lhs.x == rhs.x
>        }
>    }
> 
>    let array: [X] = (1...100).map{ X(x: 7, hashValue: $0) } // unique hash values
>    array.count //→ 100
> 
>    let set = Set(array)
>    set.count //→ 43
> 
>    let set2 = Set(Array(set))
>    set2.count //→ 30
> 
>    let set3 = Set(Array(set2))
>    set3.count //→ 30
> 
>    set3.sorted{ $0.hashValue < $1.hashValue }
>        .forEach{ print(String($0.hashValue, radix: 2), "=", $0.hashValue) } /*→
>           1 = 1
>          11 = 3
>         101 = 5
>        1111 = 15
>       10010 = 18
>       10011 = 19
>       11000 = 24
>       11101 = 29
>       11111 = 31
>      100000 = 32
>      100011 = 35
>      100100 = 36
>      100110 = 38
>      101000 = 40
>      101001 = 41
>      101011 = 43
>      101111 = 47
>      110010 = 50
>      110101 = 53
>      111101 = 61
>     1000010 = 66
>     1001011 = 75
>     1001101 = 77
>     1001111 = 79
>     1010000 = 80
>     1011001 = 89
>     1011100 = 92
>     1011110 = 94
>     1011111 = 95
>     1100010 = 98
>    */
> 
> Many thanks,
> 
> milos
> 
> _______________________________________________
> swift-users mailing list
> swift-users at swift.org
> https://lists.swift.org/mailman/listinfo/swift-users



More information about the swift-users mailing list