Is there a way to implement a foreign trait only for local types and not for foreign types?

I declared this trait:

pub(crate) trait PaddedString {
    fn padded(&self) -> String;
}

And I want to implement std::fmt::Display for types which implement PaddedString like this:

impl<T: PaddedString> std::fmt::Display for T {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.padded())
    }
}

However, the compiler reports an error:

error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
  --> src/main.rs:74:6
   |
74 | impl<T: PaddedString> std::fmt::Display for T {
   |      ^ type parameter `T` must be used as the type parameter for some local type
   |
   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
   = note: only traits defined in the current crate can be implemented for a type parameter

I don't fully understand the orphan rules, and I don't know why this code doesn't compile.

I think the type parameter T is a local type because it is bound to PaddedString which is pub(crate). Is this idea wrong?

Is there a way to implement a foreign trait only for local types and not for foreign types?

Generics and trait bounds don't take visibility into account, so T is not a local type from their perspective. (And if they did, changing visibility would break far away code, so they probably never will.)

There's no bound for local types (I have also wished for such a mechanism). The best workarounds I know are

  • macro the implementation
  • implement for a wrapper newtype instead
  • make a subtrait of Display if you don't need Display itself
4 Likes

Thank you for your response and the workarounds :slightly_smiling_face:

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.