3

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?

TylerP
  • 9,600
  • 4
  • 39
  • 43
orion elenzil
  • 4,484
  • 3
  • 37
  • 49

1 Answers1

6

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

Sulthan
  • 128,090
  • 22
  • 218
  • 270
  • 3
    For more [details](https://github.com/apple/swift-evolution/blob/main/proposals/0206-hashable-enhancements.md), hasher uses an internal seed value initialised in the runtime during process startup. The seed value is usually produced by a random number generator. Because of this hasher for the same object is unique for same execution. In the next execution this seed value is different so that hash will be different. But this behaviour may be disabled by defining the ```SWIFT_DETERMINISTIC_HASHING``` environment variable with a value of ```1``` – udi Sep 29 '22 at 19:32
  • Got it. Thank you! I can see the rationale. At the same time, I do have a security-agnostic use for a deterministic hash, so I wish that were a built-in. I'm not comfortable with `SWIFT_DETERMINISTIC_HASHING` because altho my one little feature doesn't need security, I don't want to commit my whole project to that approach. But thank you for pointing it out, @udi ! Cheers! – orion elenzil Oct 10 '22 at 15:13