1.17.1. Coherence

Coherence means that for a given type and method, there is only one correct choice for the implementation of that method on that type.

The orphan rule means that as long as either the trait or the type is in the local crate, you can implement that trait for that type. For example:

  • A type you define locally can implement the Debug trait
  • You can implement a trait you define locally for bool
  • You cannot implement Debug for bool, because neither side is local

There are exceptions to the orphan rule, which we will discuss below.

1.17.2. Blanket Implementation

A blanket implementation, also called a general implementation, means that Rust allows a default implementation for every type that satisfies a trait bound.

Its template is:

impl<T> MyTrait for T where T: ...

Enter fullscreen mode Exit fullscreen mode

This means implementing MyTrait for all types that implement some trait.

For example:

impl<T: Display> ToString for T {}

Enter fullscreen mode Exit fullscreen mode

This means implementing ToString for all types that implement Display.

This example is not yet written in template form. In template form, it would be:

impl<T> ToString for T where T: Display {}

Enter fullscreen mode Exit fullscreen mode

Note that only the crate that defines the trait is allowed to use blanket implementations. Adding a blanket implementation to an existing trait is a breaking change.

1.17.3. Fundamental Types

Some types are so fundamental that we need to allow anyone to implement traits for them, even if that would violate the orphan rule. These types are marked #[fundamental], and currently include &T, &mut T, Box<T>, and Pin<P>.

  • One extra note: the main purpose of Pin<P> is to ensure that a value cannot be moved, that is, to prevent operations such as std::mem::replace, std::mem::swap, or std::mem::take from changing the value’s physical address
  • For the purpose of the orphan rule, these types are actually erased before orphan-rule checking takes place

Note: using blanket implementations on fundamental types is also considered a breaking change.

1.17.4. Covered Implementation

Sometimes you need to implement an external trait for an external type, which is called a covered implementation. This uses one narrow exemption established by the orphan rule: it allows an external trait to be implemented for an external type in very specific cases.

Note: covered implementation can refer either to Covered Implementation or Override Implementation. Here it refers to Covered Implementation. Override implementation means that when a struct implements a trait and provides its own methods, it can override the default implementation.

The template for this form is:

impl<P1..=Pn> ForeignTrait<T1..=Tn> for T0

Enter fullscreen mode Exit fullscreen mode

  • P1..=Pn and T1..=T0 refer to a number of parameters

This form is allowed only if all of the following conditions are met:

  • At least one of T1..=Tn is a local type
  • No T (where T is one of the generic types in P1..=Pn) may appear before the first such local type
  • A generic type parameter P may appear in T0..Ti as long as it is wrapped by some intermediate type
    • If T appears as a type parameter of another type, such as Vec<T>, then T is considered wrapped
    • If T appears only by itself, or behind a fundamental type such as &T, then it is not wrapped

For a simple example:

impl From<MyType> for Vec<i32>

Enter fullscreen mode Exit fullscreen mode

This implements the external From<MyType> trait for the external Vec<i32> type.

Here are some more complex examples. You can use the rules above to understand them:

Implementation Valid?
impl<T> From<T> for MyType OK
impl<T> From<T> for MyType<T> OK
impl<T> From<MyType> for Vec<T> OK
impl<T> ForeignTrait<MyType, T> for Vec<T> OK
-------------------------------------------- ------------
impl<T> ForeignTrait for T Not OK
impl<T> From<T> for T Not OK
impl<T> From<Vec<T>> for T Not OK
impl<T> From<MyType<T>> for T Not OK
impl<T> From<T> for Vec<T> Not OK
impl<T> ForeignTrait<T, MyType> for Vec<T> Not OK

Whether a covered implementation is a breaking change depends on the specific situation:

  • Adding a new implementation to an existing trait, with at least one new local type that satisfies the conditions above, is a non-breaking change
  • Adding an implementation for an existing trait that does not meet the conditions above is a breaking change

Note:

  • impl<T> ForeignTrait<MyType, T> for Vec<T> is valid
  • impl<T> ForeignTrait<T, MyType> for Vec<T> is invalid