[CSHARP-3288] MongoDB.Bson.Decimal128 doesn't implement GetHashCode correctly Created: 10/Dec/20  Updated: 31/Mar/22

Status: Backlog
Project: C# Driver
Component/s: BSON
Affects Version/s: 2.11.5
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Nikola Irinchev Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

The GetHashCode implementation of MongoDB.Bson.Decimal128 uses the low and the high bytes to calculate a hashcode. This is problematic, because the standard allows for multiple representations of the same number. For example,
_high: 6916966077687660544, _low: 10 represents 1.0m
_high: 1, _low: 0 represents 1

This is correctly handled in the Equals implementation and `((Decimal128)1.0m).Equals((Decimal128)1)` returns `true`, however `((Decimal128)1.0m).GetHashCode().Equals(((Decimal128)1).GetHashCode())` returns `false`. The most obvious issue that this causes is that a HashSet of Decimal128 values will contain duplicates.

This is slightly affecting the Realm .NET SDK, which is in the process of adding support for a collection with Set-like semantics. When an object containing such a collection is unmanaged, it uses a HashSet to store the values. Once it gets added to the Realm database, we use a C++ implementation of the collection, which correctly detects 1.0 and 1 as duplicates and only stores one of them. From a user's perspective, it can be surprising that adding an object to the database changes the number of items in the collection.

Support for `ISet<T>` properties in Realm .NET will ship toward end of January 2021 and it would be nice, but by no means a deal breaker, to have a fix for this issue. We don't expect everyone to suddenly start using sets, and of those, only a small percentage will need to use Decimal128, so I don't imagine we'll start getting swarmed with bug reports.



 Comments   
Comment by Nikola Irinchev [ 17/Dec/20 ]

Hey mikalai.mazurenka thanks for the suggestions. I'm not sure if the Realm team will have the capacity to work on this ticket this quarter, but will let you know if we take it up.

Comment by Mikalai Mazurenka (Inactive) [ 17/Dec/20 ]

Hi nikola.irinchev
Thank you for reporting this bug.
You can provide a PR with the improvement if you have a solution for the issue which does not affect the performance.
As a temporary workaround I would suggest using custom IEqualityComparer for HashSet (e.g. with GetHashCode(Decimal128 d) => ((decimal)d).GetHashCode()). There's also an option to use custom tree structure which doesn't use GetHashCode instead of HashSet if that is suitable.

Generated at Wed Feb 07 21:44:54 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.