Description
Description
Calling inferringMoves
for types which have differences between Equatable value and Hashable value does not give the expected behavior. The inferringMoves function only detects moves for items which are both EQUAL and have the same hashValue. Which seems incorrect to me. It should detect moves for items where the hash value remains the same even if the two items are not equal
Reproduction
import Foundation
struct Item: Equatable, Hashable {
let id: Int
var title: String
func hash(into hasher: inout Hasher) {
hasher.combine(self.id)
}
}
/// We have two sets of items here. Both contain the "same" 2 items, with ids 1 and 2
/// But they are sorted by title. In the second array, item 1 has had it's title updated
/// and thus is sorted after item 2
var items: [Item] = [
Item(id: 1, title: "A Title"),
Item(id: 2, title: "B Title")
]
var updatedItems: [Item] = [
Item(id: 2, title: "B Title"),
Item(id: 1, title: "Z Title")
]
/// Here you will see we have two changes from the initial array
/// 1. A removal from offset: 0 for { id: 1, title: "A Title" }
/// 2. An insert at offset: 1 for { id: 1, title: "Z Title" }
let difference = updatedItems.difference(from: items)
/// In my opinion here is where the bug lies. It fails to recognize
/// that the item with id 1 in the second array is the "same" item (with the same
/// hash value) with id 1 in the first array. And create the associations in the result
let changes = difference.inferringMoves()
Expected behavior
I would expect unique inserts & deletes for items with the same hashValue to be associated with each other and treated as moves. Regardless of whether they are equal to each other.
Environment
swift-driver version: 1.87.3 Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5)
Target: arm64-apple-macosx14.0
Additional information
I certainly understand that this may be debatable. That it is not an inferred move if the items are not equal. But I think we should err on the side of flexibility and leave it on the consumer to decide whether their type's Hashable
and Equatable
changes are that interchangeable.
The main reason this happens is in inferringMoves, there are two Dictionary
objects created using ChangeElement
(i.e. the type of item in the array I'm diffing) as the key. The problem is that while my objects have the same hash value, they are not equal and that key lookup only succeeds if the keys have the same hash value AND are equal.
I'm more than willing to take that change on. But I don't want to waste the time if this is truly by design