Is it possible to specialize HashMap Index for Copy types

I tried to specialized HashMap's Index impl for Copy types, for the sake of convenience (though there are probably good reasons not to do this). My attempts have failed and I know little about specialization, is it somehow possible to make specialization accept this?

// Original from std.
impl<'a, K, Q: ?Sized, V, S> Index<&'a Q> for HashMap<K, V, S>
    where K: Eq + Hash + Borrow<Q>,
          Q: Eq + Hash,
          S: BuildHasher
{
    type Output = V;

    default fn index(&self, index: &Q) -> &V {
        self.get(index).expect("no entry found for key")
    }
}

// Trying to specialize for Copy types.
impl<K, V, S> Index<K> for HashMap<K, V, S>
    where K: Copy + Eq + Hash,
              S: BuildHasher
{
    type Output = V;

    fn index(&self, index: K) -> &V {
         self.get(&index).expect("no entry found for key")
    }
}

I believe specialization has to keep the same interface - only the body of the function may be specialized.

I see. The signatures are quite different yet they are conflicting. Any chance of getting the signatures to be disjoint then?

Create a new function. You don't even need specialization for that.

The feature your asking for is just plain old function overloading, which Rust does not have. There are a few reasons I think its unlikely Rust will have this feature any time soon:

  1. It's not usually that useful, since you can just use a different method name.
  2. Using it is often not a great idea, because if these methods have different signatures and different implementations, like as not they should have a different name.
  3. In a language with a lot of type parameters flying around like Rust has, proving that the two signatures are actually disjoint is not trivial. We'd have to have a whole coherence system for function signatures, and before long we'd be talking about specialization between signatures.

In fact, I'm pretty sure that these two signatures overlap in the case where the HashMap's key is a reference type, since &T: Copy and &T: Borrow<T> (here K = &T and Q = T).

So yeah, you'd just use a different name. But I'm not sure its more convenient to call index_copy(k) than index(&k).

EDIT: I'm a little embarrassed to admit that I've been programming Rust for two years and until this minute I thought the map types didn't implement Index. :flushed:

2 Likes

Thanks for the detailed answer!

1 Like