Orphan Rule
What prevents users from writing arbitrary trait implementations for any type?
#![allow(unused)] fn main() { // Crate `postgresql-bindings` pub struct PostgresqlConn(/* details */); // Crate `database-traits`, depends on `postgresql-bindings` pub trait DbConnection { /* methods */ } impl DbConnection for PostgresqlConn {} // ✅, `DbConnection` is local. // Crate `mycoolnewdb` depends on `database-traits` pub struct MyCoolNewDbConn(/* details */); impl DbConnection for MyCoolNewDbConn {} // ✅, `MyCoolNewDbConn` is local. // Neither `PostgresqlConn` or `DbConnection` are local to `mycoolnewdb`. // This would lead to two implementations of `DbConnection` for PostgresqlConn! impl DbConnection for PostgresqlConn {} // ❌🔨 }
-
Rust traits should never be able to be implemented twice in its ecosystem. Two implementations of the same trait for the same type is a conflict with no solution.
-
We can prevent this within a crate by detecting if there are multiple definitions and disallowing it, but what about between crates in the entire Rust ecosystem?
-
Types are either local to a crate, they are defined there, or they’re not.
In the example’s “crates”,
PostgresqlConnis local topostgresql-bindings,MyCoolNewDbConnis local tomycoolnewdb. -
Traits are also either local to a crate, they are defined there, or they’re not.
Again in the example, the
DbConnectiontrait is local todatabase-traits. -
If something is local, you can write trait implementations for it.
If the trait is local, you can write implementations of that trait for any type.
If the type is local, you can write any trait implementations for that type.
-
Outside of these boundaries, trait implementations cannot be written.
This keeps implementations “coherent”: Only one implementation of a trait for a type can exist across crates.
ref:
- https://doc.rust-lang.org/stable/reference/items/implementations.html#r-items.impl.trait.orphan-rule