Yes. We're talking about bounds that are required for the receiver to be well formed, I can't possibly have a HashMap to call these methods on without the key being Hash + Eq. What I want is to quickly narrow in on the additional bounds, if any, this impl adds.
Thinking about this, there's an interesting parallel between this discussion and the discussion about uninhabited types. Note that strictly speaking, adding bounds directly on the HashMap
type would be a breaking change. This code is presently legal:
use std::collections::HashMap;
fn provide<K, V>() -> HashMap<K, V> {
unimplemented!()
}
fn consume<K, V>(_: HashMap<K, V>) {}
struct NotHashEq;
fn main() {
let m = provide::<NotHashEq, i32>();
consume(m);
println!("Done");
}
Adding the constraint to the HashMap
type itself would of course make both of these functions ill-formed. Adding implied bounds would make the functions compile, but the calling code would be broken.
You could, recognizing that the basis of adding the implied bounds is the inhabitedness of HashMap<K, V>
, follow the suggestion by @Fylwind to put the constraint on the HashMap
constructor. This would mean this code would remain legal, you just wouldn't be able to meaningfully implement provide
, which is exactly the case today due to the public interface of HashMap
. Then, depending on how Rust ends up reasoning about uninhabitedness, the bounds could be deemed to hold for all uses of the result of provide
, since either they do hold, or the code is unreachable anyways.
This could of course create surprising results, since someone could design a whole system based around provide
, and only later realize that provide
can't be implemented meaningfully. This is somewhat worse than the status quo, since right now, you couldn't do anything meaningful with the result of provide
, limiting the amount of code that could depend on the (effectively) uninhabited type. The compiler could warn you when the code is invariantly unreachable, e.g. since HashMap
is known to be uninhabited for the provided K
, rather than simply not being universally inhabited because K
lacks the appropriate bounds. Note how this relates to above discussion about how the compiler reasons about uninhabited types/variants.
The fact that presently you can't do much with an unbounded HashMap
is also probably sufficient to make the breaking change of adding the bounds to the type acceptable, since Rust has tended to be pragmatic about this sort of thing. I think it's just worth noting the breakage and the implications of trying to avoid it.