The Orphan Rule
Goal of This Episode
Understand Rust’s orphan rule, and what to do when you want to implement an external trait for an external type.
Concept
In Chapter 5 we learned traits — you can implement any trait for your own types. But have you ever tried this:
use std::fmt;
impl fmt::Display for Vec<i32> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "my vec")
}
}
fn main() {}
The compiler refuses flat out. Why?
The Orphan Rule
Rust has a rule:
To
implatrait, at least one of thetraitor the type must be defined in your owncrate.
Put differently: the trait is yours, or the type is yours — at least one must hold.
In the example above, Display is defined by the standard library, and so is Vec<i32> — neither is yours, so no.
Why This Restriction Exists
Imagine there were no orphan rule:
crateAimplementsDisplayforVec<i32>, printing[1, 2, 3].crateBalso implementsDisplayforVec<i32>, printing1 | 2 | 3.- Your program uses both
AandB… which should the compiler pick?
That’s a conflict. The orphan rule prevents the problem at its root.
The Legal Cases
All of these are legal:
// Case 1: your type + an external trait
struct MyPoint {
x: f64,
y: f64,
}
impl std::fmt::Display for MyPoint {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
// Case 2: an external type + your trait
trait Describable {
fn describe(&self) -> String;
}
impl Describable for Vec<i32> {
fn describe(&self) -> String {
format!("A Vec with {} elements", self.len())
}
}
fn main() {}
Adding Methods to an External Type with Your Own trait
Case 2 above is especially useful. Although Vec<i32> is a standard-library type, Describable is a trait we defined in the current crate, so the orphan rule allows us to write impl Describable for Vec<i32>. After that implementation, a Vec<i32> value can call .describe() with method syntax.
Why Can’t You Write impl Vec<i32> Directly?
If the goal is merely to add a method, you might wonder why we cannot skip the trait and write this instead:
impl Vec<i32> {
fn describe(&self) -> String {
format!("A Vec with {} elements", self.len())
}
}
fn main() {}
Rust does not allow this either. The Type in impl Type { ... } must be defined in the current crate. Vec is defined by the standard library; bringing it into scope with use does not make it your type.
The reason is the one behind the orphan rule — two crates colliding — except that with a trait the collision stays distinguishable. A trait method is only callable when its trait is in scope, so even if crate A and crate B each define their own trait and implement describe for Vec<i32>, the decision is still yours: whichever trait you use, that is the .describe() you get.
A method written directly inside impl Vec<i32> { ... } has no such layer. It belongs to no trait, and calling it requires no use at all: as long as that crate is among your dependencies, v.describe() simply exists. If two crates each added one, you would have no way to say which one you meant. That is why a method attached directly to a type can only be added by the crate that defines that type.
The boundary here is the crate, not a particular file or mod. As long as a type is defined in the current crate, its impl Type { ... } block may live in another mod within that same crate.
Therefore, when you do not want to wrap an external type but do want to add a method to it, you can define your own trait and implement that trait for the external type, as above.
The Newtype Pattern (the Workaround)
If you truly need to implement an external trait for an external type, use the newtype pattern — a tuple struct wrapping the external type:
use std::fmt;
struct MyVec(Vec<i32>);
impl fmt::Display for MyVec {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let items: Vec<String> = self.0.iter()
.map(|x| x.to_string())
.collect();
write!(f, "[{}]", items.join(", "))
}
}
fn main() {}
MyVec is a type you defined, so implementing Display for it is allowed. self.0 reaches the inner Vec<i32>.
Example Code
use std::fmt;
// The newtype pattern: wrapping an external type in your own struct
struct Scores(Vec<i32>);
impl Scores {
fn new() -> Scores {
Scores(Vec::new())
}
fn add(&mut self, score: i32) {
self.0.push(score);
}
fn total(&self) -> i32 {
self.0.iter().sum()
}
}
// Now Display can be implemented for "your type"
impl fmt::Display for Scores {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let items: Vec<String> = self.0.iter()
.map(|x| x.to_string())
.collect();
write!(f, "Scores: [{}], total: {}", items.join(", "), self.total())
}
}
fn main() {
let mut scores = Scores::new();
scores.add(85);
scores.add(92);
scores.add(78);
scores.add(95);
// With Display implemented, println works directly
println!("{}", scores);
}
The Multi-parameter trait Case
The rule above is the simplest version. For multi-parameter traits (like Chapter 5’s From<T>), the rules are actually more intricate. In brief:
// OK: your type appears among the parameters
impl From<MyType> for String { ... }
// Not allowed: both sides are external
impl From<String> for Vec<i32> { ... }
The complete rules involve concepts like “covered type parameters,” beyond this tutorial’s scope. The curious can consult the official documentation.
Recap
- The orphan rule: in
impl Trait for Type, at least one of thetraitor the type must be defined in yourcrate. - “Your type + an external
trait” ✅ legal. - “An external type + your
trait” ✅ legal. - “An external type + an external
trait” ❌ illegal. - Defining your own
traitand implementing it for an external type adds methods to that type. - The
Typeinimpl Type { ... }must be defined in the currentcrate, though theimpland the type may live in different files ormods. - The orphan rule exists to prevent
implconflicts betweencrates. - The newtype pattern: wrap the external type in
struct MyWrapper(OriginalType), and it becomes your type. - The orphan rule for multi-parameter
traits is far subtler — see the official documentation.