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() {

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?


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?