Why do traits bounds need to be specified in impl blocks?

Let's say I have the following code:

trait MyTrait {}

struct MyStruct<T: MyTrait> {
    foo: T
}

impl<T> MyStruct<T> {
    fn bar(&self) {}
}

It doesn't compile, but complains about a trait bound not being specified in the impl block.

Replacing impl<T> by impl<T: MyTrait> works, but why can't the compiler infer that bound since it is in the definition of MyStruct, so a MyStruct<T> where T isn't MyTrait doesn't even make sense ?

I feel like this is unnecessary, especially for impl bocks that don't even deal with MyTrait, but maybe there is a corner case which i'm not aware of ?

See https://github.com/rust-lang/rfcs/pull/2089

tl;dr seems to be that this is something that we would like to have but there are complications regarding the implementation.

2 Likes

The idiomatic way to write this is to not have any trait bounds on the struct definition itself unless it’s actually required in order to write the definition. Rather, the bounds should be on the methods that actually make use of them, or on the encompassing impl block if many methods share the same set of bounds. This ensures your type is as flexible as possible.

6 Likes

As jdahlstrom mentioned, this is why it's normal in Rust to not put bounds on types unless they're absolutely needed.

You'll notice that the HashMap type doesn't require K: Eq+Hash, for example, just certain methods and trait implementations. And thus you can Debug-print a HashMap with just K: Debug, V: Debug in your method without needing to put where K: Eq + Hash on it.

The big thing is resilience to future changes. By requiring that the code that uses the bounds repeats those bounds, it means it's a non-breaking change to remove bounds from a struct type.

For example, if you had struct MyStruct<T: Copy> { … }, all the code that uses it will have the T: Copy bound it needs already, so you can change it to just struct MyStruct<T: Clone> { … } as a minor change, not a breaking one, and all the existing methods written against it will continue to require T: Copy. But if those consumers had been getting T: Copy implicitly, then they'd (likely) break once they only had T: Clone instead.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.