Skip to content
rusthacks.dev
Generics

Rust Error E0117 Only Traits Defined Here Can Be Implemented

E0117 means you tried to implement a foreign trait for a foreign type. See the exact message, three causes and the newtype or local trait fix.

6 min read
Summarize in AI
Flat illustration for the post “Rust Error E0117 Only Traits Defined Here Can Be Implemented”, composed around errors.

error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate appears when you try to implement a trait from somewhere else on a type from somewhere else. The classic attempt is impl Display for Vec<u32>: both Display and Vec belong to the standard library, so your crate may not connect them. The rule is the orphan rule, and it exists so that two unrelated crates cannot define conflicting implementations of the same pair. The fix is to bring one side into your crate: wrap the type in a struct you own, or define the trait yourself. This post reproduces the error with Rust 1.99, shows both fixes with a working program, explains the exact wording of the rule including the loopholes, and covers the less obvious cases such as generic parameters.

The error

src/main.rsrust
use std::fmt;

impl fmt::Display for Vec<u32> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} items", self.len())
    }
}

fn main() {
    println!("{}", vec![1u32, 2]);
}
Text
error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
 --> a117.rs:3:1
  |
3 | impl fmt::Display for Vec<u32> {
  | ^^^^^^^^^^^^^^^^^^^^^^--------
  |                       |
  |                       `Vec` is not defined in the current crate
  |
  = note: impl doesn't have any local type before any uncovered type parameters
  = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules
  = note: define and implement a trait or new type instead

The underlined Vec marks the foreign type, and the last note names both solutions: "define and implement a trait or new type instead". The program is perfectly reasonable, which is why the rule feels unfair the first time. It exists for a reason that does not show up until you imagine every published crate together. If your crate could implement Display for Vec<u32>, another crate could do the same with a different format, and a program depending on both would have two competing implementations of one trait for one type, with no way to choose. The compiler prevents this by allowing an implementation only where the crate owns at least one of the two parts.

The rule, stated precisely

You may write impl Trait for Type if the trait is defined in your crate, or the type is defined in your crate. Both of the following are allowed, and both are what the fixes use:

You writeTrait ownerType ownerAllowed
impl Display for Idsstdyour crateYes, the type is local
impl Summary for Vec<u32>your cratestdYes, the trait is local
impl Display for Vec<u32>stdstdNo, E0117
impl Display for Vec<Ids>stdstdNo, Vec<Local> is still a foreign type

The fourth row catches people: wrapping a local type in a foreign container does not make the container local. Only a local type at the "front" of the implementing type counts, which is what the note "impl doesn't have any local type before any uncovered type parameters" refers to. Box<Ids> and &Ids are special-cased as "fundamental" and count as local, so impl Display for Box<Ids> is allowed.

Fix one: a newtype

Wrap the foreign type in a tuple struct of your own. The struct is local, so the implementation is legal:

src/main.rsrust
use std::fmt;

// The orphan rule allows this: the type is ours, even though it wraps a foreign one.
struct Ids(Vec<u32>);

impl fmt::Display for Ids {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} items", self.0.len())
    }
}

// Or define a trait of your own: then any type may implement it.
trait Summary {
    fn summary(&self) -> String;
}

impl Summary for Vec<u32> {
    fn summary(&self) -> String {
        format!("{} items, sum {}", self.len(), self.iter().sum::<u32>())
    }
}

fn main() {
    println!("{}", Ids(vec![1, 2]));
    println!("{}", vec![1u32, 2, 3].summary());
}
Text
2 items
3 items, sum 6

struct Ids(Vec<u32>) costs nothing at run time: the wrapper has the same layout as the vector, and the compiler erases the distinction. Its price is on the source side. A newtype does not inherit the inner type's methods, so ids.len() needs either ids.0.len() or a Deref implementation that forwards to the vector (acceptable for a thin wrapper, debated for a domain type). You construct it explicitly with Ids(vec![1, 2]). This is the right solution when the new behavior belongs to a specific meaning of the data, such as "a list of user IDs", which is a better domain model than a bare Vec<u32> anyway.

Fix two: your own trait

If the goal is to add methods to an existing type, define a trait and implement it for the type. The trait is local, so the rule is satisfied, and callers get a method on the original type:

src/main.rsrust
trait Summary {
    fn summary(&self) -> String;
}

impl Summary for Vec<u32> {
    fn summary(&self) -> String {
        format!("{} items, sum {}", self.len(), self.iter().sum::<u32>())
    }
}

vec![1u32, 2, 3].summary() prints 3 items, sum 6, as the last line of the program above shows. This is called an extension trait, and it is how crates add methods to types they do not own: itertools::Itertools for iterators and futures::StreamExt for streams are both extension traits. The users of your trait must import it with use before calling the method. Extension traits do not change how the type prints or compares; for that you need the newtype.

Choosing between them

If you want a different Display, Debug, PartialEq, Serialize or Hash for a type you do not own, only the newtype works, because those traits are foreign. If you want to add new methods, either works, and the extension trait is lighter because callers keep using the original type. If you also control the data model, prefer the newtype: it carries meaning and lets the compiler stop you from passing a list of order IDs where a list of user IDs was meant.

What the rule does not stop

The rule is about implementations, and plenty is still allowed. You can call foreign traits on foreign types. You can use a foreign type as a parameter or field of your own types. You can implement a foreign trait for your own type, whatever other types appear in the trait's parameters: impl From<Ids> for u32-style conversions, where Ids is local, work because the local type appears in the implementation. You can implement a foreign trait for a reference to a local type. And you can write a blanket implementation of your own trait for all T, which is how a trait can be defined once and apply to everything; see blanket implementations.

When the type and trait both come from crates you do not control

You may be in an application that needs Serialize for a type from a library that does not implement it. The orphan rule blocks the direct route, so the options are the same, with a common twist. Wrap the type and implement the foreign trait on the wrapper, or use an attribute the trait's crate provides for exactly this problem: serde has #[serde(with = "module")] for a field of a foreign type, which delegates to functions you write. If you control the library, add the implementation there. If you do not and the missing trait is widely wanted, open an issue or send a patch; published crates handle this by putting the implementation in the crate that owns either side, often behind a feature flag.

For related behavior, the orphan rule explained covers the loopholes in more depth, E0119 conflicting implementations is the error you get when two of your own implementations overlap, and extension traits develops the second fix.

Taggede0117
Share

Keep reading

Get new posts by email

We send one email when a new post is published. No spam.

Unsubscribe in one click. No spam, ever.