Rust in Depth

the orphan / coherence rule

Imagine two unrelated libraries you depend on both decided to teach the standard Vec type how to be printed in their own way. Now your program imports both, and at a call site the compiler has two conflicting implementations of the same trait for the same type — which one runs? In a language that allowed this, the answer could depend on import order, and the same code could behave differently in different projects. Rust forbids the situation entirely. Coherence is the guarantee that for any (trait, type) pair there is at most one implementation in the whole program; the orphan rule is the concrete restriction that enforces it.

The orphan rule says: you may implement a trait for a type only if at least one of the trait or the type is defined in your own crate. In other words, you can implement YOUR trait for somebody else's type (you own the trait), or implement somebody else's trait for YOUR type (you own the type), but you may NOT implement a foreign trait for a foreign type — that combination is an 'orphan', owned by neither, and is rejected. So you cannot write impl Display for Vec<i32> in your crate, because both Display and Vec belong to the standard library. The reasoning is exactly the conflict above: if any crate could implement any foreign trait for any foreign type, two crates could supply clashing impls and coherence would break. By tying every impl to a crate that owns one of its two halves, Rust ensures the standard library, your crate, and every dependency can each add impls without ever stepping on each other.

Why this matters: coherence is what makes traits reliable — you never wonder which impl is in effect, because there is only ever one. The cost is the famous frustration of 'I can't implement this external trait on this external type'. The standard workaround is the newtype pattern: wrap the foreign type in your own one-field struct (struct MyVec(Vec<i32>)), and now the type is local, so you may implement the foreign trait on it. The honest framing is that the orphan rule is a deliberate trade: it costs you some convenience to buy a global guarantee that trait resolution is unambiguous and stable across the entire dependency graph.

use std::fmt; // Forbidden: both Display and Vec are foreign (orphan impl). // impl fmt::Display for Vec<i32> { ... } // error[E0117] // Allowed via the newtype pattern: the wrapper is YOURS. struct Wrap(Vec<i32>); impl fmt::Display for Wrap { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:?}", self.0) } }

You may not implement a foreign trait on a foreign type; wrap it in your own newtype to make one half local.

The orphan rule is not arbitrary fussiness: it is what guarantees there is exactly one impl per (trait, type) across the whole program, so trait resolution never depends on import order. The newtype wrapper is the standard escape.

Also called
orphan rulecoherencetrait coherence孤兒規則一致性