Change:
VecDeque's hashcode changes after rotation. In the following example, the VecDeque should be in its original ordering, yet it produces a different hashcode. I've also opened but I was advised to open a new issue here. I tried this code: I expected to see this happen: The hashcode should not change and the example should terminate successfully Instead, this happened: The hashcode is different and the application panics. Yes, the bug exists in beta and nightly. : The issue is caused by an ambiguity in the contract - it's not clear whether the hashcode should be sensitive to the slice's length. The default hasher is not sensitive, while ahash is. <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOT_END --
Ah, you edited it just now.
Ugh, not another bug
I also filed with code references, but I closed in favor of this issue. My conclusions: If both and may consider length, then is incorrect. If should hash without length, but is allowed to use length, then the integer optimization ( calling as ) is incorrect. If both and are supposed to be independent of length, hashing identically whether it's one big slice or any partitioned slices of the same data, then is incorrect.
So ultimately this falls into the realm?
claim I will work on this
I do think this needs a decision first on the specified behavior.
This may also be suspect if a hasher is endian-sensitive -- e.g. if it would normalize to big/little-endian, but the cast to makes it always hash native-endian. But I suppose this is not a problem if you're always consistent in whether you use or not.
We discussed this in the libs meeting 2 weeks ago and came to the conclusion that is in the wrong here: only guarantees hash equivalence for the exact same set of calls to methods. This allows hasher to perform various optimizations when hashing slices, such as using unaligned load instructions.
Incidentally  could use some additional documentation to clarify that it is not necessarily equivalent to hashing each element individually in sequence.
We could potentially add a new method to Hasher that does behave that way, but I don't know if it'd really be useful in many contexts outside of something like VecDeque.
Assigning as discussed as part of the and removing .

Discussion:
impl<A: Hash> Hash for VecDeque<A> { fn hash<H: Hasher>(&self, state: &mut H) { self.len().hash(state); <del> let (a, b) = self.as_slices(); Hash::hash_slice(a, state); Hash::hash_slice(b, state); </del> <ins> // It's not possible to use Hash::hash_slice on slices // returned by as_slices method as their length can vary // in otherwise identical deques. // // Hasher only guarantees equivalence for the exact same // set of calls to its methods. self.iter().for_each(|elem| elem.hash(state)); </ins> } }

assert_eq!(*a, 2); } } <ins> #[test] fn issue_80303() { use core::iter; use core::num::Wrapping; // This is a valid, albeit rather bad hash function implementation. struct SimpleHasher(Wrapping<u64>); impl Hasher for SimpleHasher { fn finish(&self) -> u64 { self.0.0 } fn write(&mut self, bytes: &[u8]) { // This particular implementation hashes value 24 in addition to bytes. // Such an implementation is valid as Hasher only guarantees equivalence // for the exact same set of calls to its methods. for &v in iter::once(&24).chain(bytes) { self.0 = Wrapping(31) * self.0 + Wrapping(u64::from(v)); } } } fn hash_code(value: impl Hash) -> u64 { let mut hasher = SimpleHasher(Wrapping(1)); value.hash(&mut hasher); hasher.finish() } // This creates two deques for which values returned by as_slices // method differ. let vda: VecDeque<u8> = (0..10).collect(); let mut vdb = VecDeque::with_capacity(10); vdb.extend(5..10); (0..5).rev().for_each(|elem| vdb.push_front(elem)); assert_ne!(vda.as_slices(), vdb.as_slices()); assert_eq!(vda, vdb); assert_eq!(hash_code(vda), hash_code(vdb)); } </ins>