Skip to content
Free public beta until December 4, 2026: every course is open, no card needed. After that, the first chapter of each course stays free and full access is a one-time $39 ($19 for up to 100 founding members chosen for helpful feedback). Your progress is kept. How the beta works

Recipe

Implement a foreign trait for a foreign type (via a newtype)

Use when: rustc reports E0117 because you want a standard library (or other crate's) trait on a type you didn't define

Goal: the behaviour you wanted, on a local wrapper type the orphan rule allows

Taught in Coherence and the orphan rule

  1. 1

    Declare a newtype around the foreign type: struct Readings(Vec<f64>);.

    Example

    The failing program has impl fmt::Display for Vec<f64>. Add one line above it: struct Readings(Vec<f64>);. The impl hasn't moved yet, so rustc still reports E0117 at this point.

    Why: the wrapper is defined in your crate, so it's local, and a foreign trait may be implemented for a local type.

  2. 2

    Move the impl to the wrapper, impl fmt::Display for Readings, and reach the inner value as self.0.

    Example

    The header becomes impl fmt::Display for Readings. Inside, self is now a Readings, so self.len() becomes self.0.len(): write!(f, "{} readings", self.0.len()). The E0117 is gone.

    Why: the body is the same logic as before; only the type it's attached to has changed.

  3. 3

    Where the program made a Vec<f64>, make a Readings(vec![...]) instead, and pass that to the code that uses the trait.

    Example

    let temps = vec![18.5, 19.0, 21.25]; becomes let temps = Readings(vec![18.5, 19.0, 21.25]);. The line println!("{temps}") stays as it was, and now prints 3 readings.

    Why: the trait belongs to Readings, not to Vec<f64>, so it only applies to values of the wrapper type.

  4. 4

    If callers need a few of the inner type's methods, add small methods to the wrapper (fn len(&self) -> usize { self.0.len() }), or use .0.

    Example

    A caller wants the first reading. temps.0[0] gives 18.5. If callers often want the count, add impl Readings { fn len(&self) -> usize { self.0.len() } }, and temps.len() returns 3. Methods you don't add, like push, stay out of reach unless someone goes through .0.

    Why: the wrapper is a real type, so you choose which operations it offers.

Common mistakes

  • Declaring the wrapper but leaving the impl on the foreign type (still E0117).
  • Forgetting to change where values are created, so the code still holds a plain Vec.
  • Wrapping only the element type (Vec<MyType>): the outer Vec is still foreign.