-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Mismatched types and inaccessible methods for HashMap and HashSet in 0.16-rc #18690
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Slight variant on forking |
I'm in favor of "use hashbrown's default hash" as the Bevy 0.16 solution, but would accept "just revert to hashbrown 0.14", reverting #15801. I feel strongly that we shouldn't ship in the current state. Long-term, the ideal solution is clearly "hasbrown / std make it easier to use alternate hashers", but I would grudgingly tolerate forking if that seems impossible. Newtyping @Amanieu, do you have opinions / insight here? You're much better acquainted with the various algorithms and the upstream maintenance considerations here. |
As an aside: I didn't realize the magnitude of UX issues here, and shouldn't have merged #15801 so readily. Dependency bumps are usually much less frustrating than this! |
We do use hashbrown's default hasher, just not its default buildhasher. |
Hashbrown switched from |
Can you explain the difference between a hasher and a buildhasher for me? Why shouldn't we use the default buildhasher? Oh I see: that's the random vs fixed initialization. Bah, okay. We can sacrifice determinism here in favor of ergonomics by default IMO. I really appreciate you chiming in here Amaneiu. |
Also keep in mind that hashbrown may change the default hasher again in the future. You should not assume a specific hasher is used and should instead always use |
Was there public discussion where this restriction for (Returning to |
This restriction also exists in the standard library (since Rust 1.0). If |
Makes sense! |
# Objective - Fixes #18690 - Closes [#2065](bevyengine/bevy-website#2065) - Alternative to #18691 The changes to the Hash made in #15801 to the [BuildHasher](https://doc.rust-lang.org/std/hash/trait.BuildHasher.html) resulted in serious migration problems and downgraded UX for users of Bevy's re-exported hashmaps. Once merged, we need to go in and remove the migration guide added as part of #15801. ## Solution - Newtype `HashMap` and `HashSet` instead of type aliases - Added `Deref/Mut` to allow accessing future `hashbrown` methods without maintenance from Bevy - Added bidirectional `From` implementations to provide escape hatch for API incompatibility - Added inlinable re-exports of all methods directly to Bevy's types. This ensures `HashMap::new()` works (since the `Deref` implementation wont cover these kinds of invocations). ## Testing - CI --- ## Migration Guide - If you relied on Bevy's `HashMap` and/or `HashSet` types to be identical to `hashbrown`, consider using `From` and `Into` to convert between the `hashbrown` and Bevy types as required. - If you relied on `hashbrown/serde` or `hashbrown/rayon` features, you may need to enable `bevy_platform_support/serialize` and/or `bevy_platform_support/rayon` respectively. --- ## Notes - Did not replicate the Rayon traits, users will need to rely on the `Deref/Mut` or `From` implementations for those methods. - Did not re-expose the `unsafe` methods from `hashbrown`. In most cases users will still have access via `Deref/Mut` anyway. - I have added `inline` to all methods as they are trivial wrappings of existing methods. - I chose to make `HashMap::new` and `HashSet::new` const, which is different to `hashbrown`. We can do this because we default to a fixed-state build-hasher. Mild ergonomic win over using `HashMap::with_hasher(FixedHasher)`.
# Objective - Fixes #18690 - Closes [#2065](bevyengine/bevy-website#2065) - Alternative to #18691 The changes to the Hash made in #15801 to the [BuildHasher](https://doc.rust-lang.org/std/hash/trait.BuildHasher.html) resulted in serious migration problems and downgraded UX for users of Bevy's re-exported hashmaps. Once merged, we need to go in and remove the migration guide added as part of #15801. ## Solution - Newtype `HashMap` and `HashSet` instead of type aliases - Added `Deref/Mut` to allow accessing future `hashbrown` methods without maintenance from Bevy - Added bidirectional `From` implementations to provide escape hatch for API incompatibility - Added inlinable re-exports of all methods directly to Bevy's types. This ensures `HashMap::new()` works (since the `Deref` implementation wont cover these kinds of invocations). ## Testing - CI --- ## Migration Guide - If you relied on Bevy's `HashMap` and/or `HashSet` types to be identical to `hashbrown`, consider using `From` and `Into` to convert between the `hashbrown` and Bevy types as required. - If you relied on `hashbrown/serde` or `hashbrown/rayon` features, you may need to enable `bevy_platform_support/serialize` and/or `bevy_platform_support/rayon` respectively. --- ## Notes - Did not replicate the Rayon traits, users will need to rely on the `Deref/Mut` or `From` implementations for those methods. - Did not re-expose the `unsafe` methods from `hashbrown`. In most cases users will still have access via `Deref/Mut` anyway. - I have added `inline` to all methods as they are trivial wrappings of existing methods. - I chose to make `HashMap::new` and `HashSet::new` const, which is different to `hashbrown`. We can do this because we default to a fixed-state build-hasher. Mild ergonomic win over using `HashMap::with_hasher(FixedHasher)`.
Background
rust-lang/hashbrown#563 changed the default hasher for
hashbrown
to one that doesn't meet our needs. #15801 updated us to that version of hashbrown, following our dependencies. We were originally usinghashbrown::HashMap
overstd::HashMap
due to the use of a faster, more vulnerable hashing algorithm, as Bevy apps are generally not exposed to malicious input in this way.#17460 shuffled our types around, moving
HashMap
andHashSet
intobevy_platform_support, as they replace functionality provided by Rust's
std`.As part of #15801, we also changed hashers.
#18350 attempts to explain this problem somewhat in the docs.
Problems
As discussed in bevyengine/bevy-website#2065, the migration for this is terrible: it's more explicit in confusing ways, there are prominent methods like
new
andwith_capacity
that are simply unusable, despite showing up in the docs!Potential solutions
Use
hashbrown
's default hasherThis might or might not be slower than whatever we're using. It fixes the migration / UX issues, and avoids duplicate dependencies though!
The really critical stuff is already generally using
EntityHashMap
etc, which is very optimized. See #17078 for an example.Downgrade to
hashbrown
0.14This gets us parity with Bevy 0.15, but duplicates the dependency in our tree.
It also doesn't allow us to use the deterministic
FixedHash
(or whatever else we may choose) by default.Petition for a better API upstream that can handle non-standard hashers with generics
This would be great, but due to the need to specify generic type defaults when calling methods, it may not be readily accepted.
This is made much worse by the fact that
hashbrown
is used in and aligns with thestd
API for these types, which has very strict stability guarantees.Fork
hashbrown
and change the default hasherThis also duplicates the code, but allows us to properly fix the issue and pull in new fixes and improvements from upstream.
This is strictly better than relying on 0.14 forever, but adds maintenance burden for a complex utilities crate.
The text was updated successfully, but these errors were encountered: