# Nondeterministic behaviour when hashing a class

**URL:** <https://forums.swift.org/t/nondeterministic-behaviour-when-hashing-a-class/88867>\
**Category:** Using Swift\
**Tags:** hashing\
**Created:** [August 9, 2026, 1:40am UTC](https://forums.swift.org/t/nondeterministic-behaviour-when-hashing-a-class/88867 "2026-08-09T01:40:19Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![ibex](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ibex/32/30439_2.png) [@ibex](https://forums.swift.org/u/ibex)\
**Post date:** [August 9, 2026, 1:40am UTC](https://forums.swift.org/t/nondeterministic-behaviour-when-hashing-a-class/88867/1 "2026-08-09T01:40:19Z")

</div>

There is an interesting discussion going on here in this pitch: [[Pitch] Default implementation of Hashable for AnyObject](https://forums.swift.org/t/pitch-default-implementation-of-hashable-for-anyobject/88853).

When playing with the example code posted by @mbrandonw, I noticed something unusual: nondeterministic program behaviour.

```swift
// it.swift

import Foundation

@main
enum Driver {
    static func main() async throws {
        hash_my_class ()
    }
}

// [https://forums.swift.org/t/pitch-default-implementation-of-hashable-for-anyobject/88853/9]
//

class MyClass: Hashable {
    var i: Int

    init(i: Int) {
        self.i = i
    }

    static func == (lhs: MyClass, rhs: MyClass) -> Bool { lhs.i == rhs.i }
        func hash (into hasher: inout Hasher) {
        hasher.combine(i)
    }
}

func hash_my_class() {
    print (#function, "...")
    var dictionary: [MyClass: Bool] = [:]
    let object = MyClass (i: 0)
    dictionary [object] = true
    object.i = 1
    dictionary [object] = false
    // 🛑 Fatal error: Duplicate keys of type 'MyObject' were found in a Dictionary.
    print (#function, "finished")
}

```

When I build and run it from the command line (also in `Xcode (Version 26.5 (17F42))`), I get the following nondeterministic result: the program sometimes crashes and sometimes doesn't.

```swift
> swiftc -parse-as-library it.swift

> ./it
hash_my_class() ...
Fatal error: Duplicate keys of type 'MyClass' were found in a Dictionary.
This usually means either that the type violates Hashable's requirements, or
that members of such a dictionary were mutated after insertion.
Trace/BPT trap

> ./it
hash_my_class() ...
hash_my_class() finished

> ./it
hash_my_class() ...
Fatal error: Duplicate keys of type 'MyClass' were found in a Dictionary.
This usually means either that the type violates Hashable's requirements, or
that members of such a dictionary were mutated after insertion.
Trace/BPT trap

> ./it
hash_my_class() ...
hash_my_class() finished

> ./it
hash_my_class() ...
Fatal error: Duplicate keys of type 'MyClass' were found in a Dictionary.
This usually means either that the type violates Hashable's requirements, or
that members of such a dictionary were mutated after insertion.
Trace/BPT trap

> ./it
hash_my_class() ...
hash_my_class() finished

> ./it
hash_my_class() ...
Fatal error: Duplicate keys of type 'MyClass' were found in a Dictionary.
This usually means either that the type violates Hashable's requirements, or
that members of such a dictionary were mutated after insertion.
Trace/BPT trap

```

Why this nondeterministic behaviour?

---

<div class="post-metadata">

**Author:** ![itaiferber](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/itaiferber/32/33840_2.png) [@itaiferber](https://forums.swift.org/u/itaiferber)\
**Post date:** [August 9, 2026, 1:57am UTC](https://forums.swift.org/t/nondeterministic-behaviour-when-hashing-a-class/88867/2 "2026-08-09T01:57:37Z")

</div>

From the [`Hasher` docs](https://developer.apple.com/documentation/swift/hasher):

> **Note**
> 
> 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.

On every invocation of your program, `Hasher` is randomly seeded so it produces a different result for hashing `object`. Sometimes, the hash value after your mutation coincides compatibly with the value from before, sometimes not.

e.g., imagine finding the index of `object` inside of `dictionary`'s internal storage by taking the hash modulus the number of buckets in the table, and pretend the number of buckets is rounded up to the next power of 2 (so, `hash % 2`); an even hash would return an index of `0` and an odd hash an index of `1`. `Hasher` could _happen_ to return two even numbers (hitting the assertion), or one even and one not (silently inserting the same object twice into the dictionary).

(Not saying that this is exactly what's happening here, but as an illustrating example.)

---

<div class="post-metadata">

**Author:** ![sveinhal](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/sveinhal/32/3992_2.png) [@sveinhal](https://forums.swift.org/u/sveinhal)\
**Post date:** [August 10, 2026, 8:30am UTC](https://forums.swift.org/t/nondeterministic-behaviour-when-hashing-a-class/88867/3 "2026-08-10T08:30:55Z")

</div>

You should not change the hash of a reference type while it is used as a key in a Dictionary. [See this similar issue](https://forums.swift.org/t/the-hash-value-of-the-elements-in-set-changed-not-as-expected/37670).

---

<div class="post-metadata">

**Author:** ![x-sheep](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/x-sheep/32/40748_2.png) [@x-sheep](https://forums.swift.org/u/x-sheep)\
**Post date:** [August 10, 2026, 9:06am UTC](https://forums.swift.org/t/nondeterministic-behaviour-when-hashing-a-class/88867/4 "2026-08-10T09:06:30Z")

</div>

This is correct. The hash value of a reference type (i.e. class or actor) must only depend on immutable properties. This also means that the Equatable implementation must use those same values, since `==` returning true implies that both hash values are also equal. \[1\]

* * *

1. Source: [Adopting Common Protocols | Apple Developer Documentation](https://developer.apple.com/documentation/swift/adopting-common-protocols#Use-All-Significant-Properties-for-Equatable-and-Hashable)

---

<div class="post-metadata">

**Author:** ![tera](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tera/32/38201_2.png) [@tera](https://forums.swift.org/u/tera)\
**Post date:** [August 14, 2026, 12:27pm UTC](https://forums.swift.org/t/nondeterministic-behaviour-when-hashing-a-class/88867/5 "2026-08-14T12:27:12Z")

</div>

Classic problem of changing EQ/hash in things stored by reference... In `obj-c` that was partially worked around – `NSDictionary` keys were always copied, `NSSet` elements were not.

---

<div class="post-metadata">

**Author:** ![hooman](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/hooman/32/43536_2.png) [@hooman](https://forums.swift.org/u/hooman)\
**Post date:** [August 14, 2026, 10:06pm UTC](https://forums.swift.org/t/nondeterministic-behaviour-when-hashing-a-class/88867/6 "2026-08-14T22:06:24Z")

</div>

One way to create a discipline around the issue is to have a `hashKey` property (that’s `Hashable`) and not making the class itself `Hashable`. This detaches the stable part of the class identity used for using the object as a key, from its transient “value”. Still you need to make sure when two instances are equal, they return the same `hashKey` which means using `ObjectIdentifier(_)` is ruled out. I didn’t get into inheritance and immutable objects.
