Search code examples
genericsrusttraitsbounding

Is it a convention to write ?Sized by itself as a trait bound?


On page 297 of Programming Rust you can find the following

impl HashMap<K, V> where K: Eq + Hash
{
  fn get<Q: ?Sized>(&self, key: &Q) -> Option<&V>
      where K: Borrow<Q>,
            Q: Eq + Hash
}

I've seen this before where ?Sized is written by itself, and the rest of trait bounds are on a different line? Is this a convention? As I understand it, the above is effectively the same as the following?

impl HashMap<K, V> where K: Eq + Hash
{
  fn get<Q>(&self, key: &Q) -> Option<&V>
      where K: Borrow<Q>,
            Q: Eq + Hash + ?Sized
}

Why is ?Sized split off? You can see this in a similar example on page 295,

...
where T: AsRef<U>
      T: ?Sized, U: ?Sized
...

Solution

  • That is pure convention, and it is not set in stone, but it does have some merit.

    The special syntax ?Sized lets the compiler remove this bound if it is not appropriate (when monomorphizing). As such, it does make sense, somewhat, to split it and put it in the generic definition rather than the where clause for ease of readability and to separate the fact that, unlike the others, it isn't a strict, rigid marker.

    Some libraries out there go even further and list all the markers in the generic definition, and all traits in the where clause.

    As stated in the comments and found by @PeterHall through the commit log, prior to rust 1.15, ?Sized was only available as a trait requirement in the type definition. This PR changed this to the behavior we have today.