swifthashuuiddeterministicnon-deterministic

Is UUID's hashValue non-deterministic?


Given what I think is an identical Swift UUID, I get different hashValues for it on subsequent runs of the code. Within a single run it's consistent.

eg:

func UUIDTest() {
    let uuid = UUID(uuidString: "00000000-0000-0000-0000-000000000001")
    
    let h = uuid.hashValue
    
    print("\(String(describing: uuid)) -> \(h)")
    
    /*
     
     Run #1:
     Optional(00000000-0000-0000-0000-000000000001) -> 8072320274727128679

     Run #2:
     Optional(00000000-0000-0000-0000-000000000001) -> -2566074080105686496

     */
}

The documentation is mum on whether the hash-value is a function strictly of the UUID, or if there's another ingredient as well.

Is there some understanding about Hashable that I don't have yet?


Solution

  • Not only UUID but the whole Swift Hashable protocol is non-deterministic and it's intentional.

    From Hasher documentation.

    Within the execution of a Swift program, Hasher guarantees that finalizing it will always produce the same hash value as long as it is fed the exact same sequence of bytes. However, the underlying hash algorithm is designed to exhibit avalanche effects: slight changes to the seed or the input byte sequence will typically produce drastic changes in the generated hash value.

    Do not save or otherwise reuse hash values across executions of your program. Hasher is usually randomly seeded, which means it will return different values on every new execution of your program. The hash algorithm implemented by Hasher may itself change between any two versions of the standard library.

    There are multiple reasons why this is a good thing. Security is one of them (see Hash-flooding attacks). It also prevent programmers from using hash values for things they are not designed for (e.g. equality comparison).

    See the full rationale in SE-0206