DRYing type parameter constraints

I got a codebase where I got lots of complex type parameter constraints. Things like:

fn foo<T>(x: T)
    where T: Display + Debug + Send + Sync + Clone + 'static
{}

I find this kind of annoying. So I came up with this way to DRY the constraints:

use std::fmt::{Display, Debug};

trait TheUsual: Display + Debug + Send + Sync + Clone + 'static {}
impl<T: Display + Debug + Send + Sync + Clone + 'static> TheUsual for T {}

fn foo(x: impl TheUsual) {
    println!("{} {:?}", x, x);
}

fn main() {
    foo(1);
}

This seems to work as far as I can see. Is this a common pattern? What's the downside, other than having to come up with another name?

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=ff1ff6b63611beebb484b863091fd689

1 Like

The only extra downside is the requirement that the new trait must also be implemented. Depending on the trait this can be a blanket impl and in that case it doesn't really matter much.

I know "type" will not work here.

Would be a valid argument to say that "type" was designed exactly for this type of use case? Just is currently not supported?