| For any given trait `Trait` there may be a related _type_ called the _trait | |
| object type_ which is typically written as `dyn Trait`. In earlier editions of | |
| Rust, trait object types were written as plain `Trait` (just the name of the | |
| trait, written in type positions) but this was a bit too confusing, so we now | |
| write `dyn Trait`. | |
| Some traits are not allowed to be used as trait object types. The traits that | |
| are allowed to be used as trait object types are called "dyn-compatible"[^1] | |
| traits. Attempting to use a trait object type for a trait that is not | |
| dyn-compatible will trigger error E0038. | |
| Two general aspects of trait object types give rise to the restrictions: | |
| 1. Trait object types are dynamically sized types (DSTs), and trait objects of | |
| these types can only be accessed through pointers, such as `&dyn Trait` or | |
| `Box<dyn Trait>`. The size of such a pointer is known, but the size of the | |
| `dyn Trait` object pointed-to by the pointer is _opaque_ to code working | |
| with it, and different trait objects with the same trait object type may | |
| have different sizes. | |
| 2. The pointer used to access a trait object is paired with an extra pointer | |
| to a "virtual method table" or "vtable", which is used to implement dynamic | |
| dispatch to the object's implementations of the trait's methods. There is a | |
| single such vtable for each trait implementation, but different trait | |
| objects with the same trait object type may point to vtables from different | |
| implementations. | |
| The specific conditions that violate dyn-compatibility follow, most of which | |
| relate to missing size information and vtable polymorphism arising from these | |
| aspects. | |
| [^1]: Formerly known as "object-safe". | |
| ### The trait requires `Self: Sized` | |
| Traits that are declared as `Trait: Sized` or which otherwise inherit a | |
| constraint of `Self:Sized` are not dyn-compatible. | |
| The reasoning behind this is somewhat subtle. It derives from the fact that Rust | |
| requires (and defines) that every trait object type `dyn Trait` automatically | |
| implements `Trait`. Rust does this to simplify error reporting and ease | |
| interoperation between static and dynamic polymorphism. For example, this code | |
| works: | |
| ``` | |
| trait Trait { | |
| } | |
| fn static_foo<T:Trait + ?Sized>(b: &T) { | |
| } | |
| fn dynamic_bar(a: &dyn Trait) { | |
| static_foo(a) | |
| } | |
| ``` | |
| This code works because `dyn Trait`, if it exists, always implements `Trait`. | |
| However as we know, any `dyn Trait` is also unsized, and so it can never | |
| implement a sized trait like `Trait:Sized`. So, rather than allow an exception | |
| to the rule that `dyn Trait` always implements `Trait`, Rust chooses to prohibit | |
| such a `dyn Trait` from existing at all. | |
| Only unsized traits are considered dyn-compatible. | |
| Generally, `Self: Sized` is used to indicate that the trait should not be used | |
| as a trait object. If the trait comes from your own crate, consider removing | |
| this restriction. | |
| ### Method references the `Self` type in its parameters or return type | |
| This happens when a trait has a method like the following: | |
| ``` | |
| trait Trait { | |
| fn foo(&self) -> Self; | |
| } | |
| impl Trait for String { | |
| fn foo(&self) -> Self { | |
| "hi".to_owned() | |
| } | |
| } | |
| impl Trait for u8 { | |
| fn foo(&self) -> Self { | |
| 1 | |
| } | |
| } | |
| ``` | |
| (Note that `&self` and `&mut self` are okay, it's additional `Self` types which | |
| cause this problem.) | |
| In such a case, the compiler cannot predict the return type of `foo()` in a | |
| situation like the following: | |
| ```compile_fail,E0038 | |
| trait Trait { | |
| fn foo(&self) -> Self; | |
| } | |
| fn call_foo(x: Box<dyn Trait>) { | |
| let y = x.foo(); // What type is y? | |
| // ... | |
| } | |
| ``` | |
| If only some methods aren't dyn-compatible, you can add a `where Self: Sized` | |
| bound on them to mark them as explicitly unavailable to trait objects. The | |
| functionality will still be available to all other implementers, including | |
| `Box<dyn Trait>` which is itself sized (assuming you `impl Trait for Box<dyn | |
| Trait>`). | |
| ``` | |
| trait Trait { | |
| fn foo(&self) -> Self where Self: Sized; | |
| // more functions | |
| } | |
| ``` | |
| Now, `foo()` can no longer be called on a trait object, but you will now be | |
| allowed to make a trait object, and that will be able to call any dyn-compatible | |
| methods. With such a bound, one can still call `foo()` on types implementing | |
| that trait that aren't behind trait objects. | |
| ### Method has generic type parameters | |
| As mentioned before, trait objects contain pointers to method tables. So, if we | |
| have: | |
| ``` | |
| trait Trait { | |
| fn foo(&self); | |
| } | |
| impl Trait for String { | |
| fn foo(&self) { | |
| // implementation 1 | |
| } | |
| } | |
| impl Trait for u8 { | |
| fn foo(&self) { | |
| // implementation 2 | |
| } | |
| } | |
| // ... | |
| ``` | |
| At compile time each implementation of `Trait` will produce a table containing | |
| the various methods (and other items) related to the implementation, which will | |
| be used as the virtual method table for a `dyn Trait` object derived from that | |
| implementation. | |
| This works fine, but when the method gains generic parameters, we can have a | |
| problem. | |
| Usually, generic parameters get _monomorphized_. For example, if I have | |
| ``` | |
| fn foo<T>(x: T) { | |
| // ... | |
| } | |
| ``` | |
| The machine code for `foo::<u8>()`, `foo::<bool>()`, `foo::<String>()`, or any | |
| other instantiation is different. Hence the compiler generates the | |
| implementation on-demand. If you call `foo()` with a `bool` parameter, the | |
| compiler will only generate code for `foo::<bool>()`. When we have additional | |
| type parameters, the number of monomorphized implementations the compiler | |
| generates does not grow drastically, since the compiler will only generate an | |
| implementation if the function is called with fully concrete arguments | |
| (i.e., arguments which do not contain any generic parameters). | |
| However, with trait objects we have to make a table containing _every_ object | |
| that implements the trait. Now, if it has type parameters, we need to add | |
| implementations for every type that implements the trait, and there could | |
| theoretically be an infinite number of types. | |
| For example, with: | |
| ``` | |
| trait Trait { | |
| fn foo<T>(&self, on: T); | |
| // more methods | |
| } | |
| impl Trait for String { | |
| fn foo<T>(&self, on: T) { | |
| // implementation 1 | |
| } | |
| } | |
| impl Trait for u8 { | |
| fn foo<T>(&self, on: T) { | |
| // implementation 2 | |
| } | |
| } | |
| // 8 more implementations | |
| ``` | |
| Now, if we have the following code: | |
| ```compile_fail,E0038 | |
| # trait Trait { fn foo<T>(&self, on: T); } | |
| # impl Trait for String { fn foo<T>(&self, on: T) {} } | |
| # impl Trait for u8 { fn foo<T>(&self, on: T) {} } | |
| # impl Trait for bool { fn foo<T>(&self, on: T) {} } | |
| # // etc. | |
| fn call_foo(thing: Box<dyn Trait>) { | |
| thing.foo(true); // this could be any one of the 8 types above | |
| thing.foo(1); | |
| thing.foo("hello"); | |
| } | |
| ``` | |
| We don't just need to create a table of all implementations of all methods of | |
| `Trait`, we need to create such a table, for each different type fed to | |
| `foo()`. In this case this turns out to be (10 types implementing `Trait`)\*(3 | |
| types being fed to `foo()`) = 30 implementations! | |
| With real world traits these numbers can grow drastically. | |
| To fix this, it is suggested to use a `where Self: Sized` bound similar to the | |
| fix for the sub-error above if you do not intend to call the method with type | |
| parameters: | |
| ``` | |
| trait Trait { | |
| fn foo<T>(&self, on: T) where Self: Sized; | |
| // more methods | |
| } | |
| ``` | |
| If this is not an option, consider replacing the type parameter with another | |
| trait object (e.g., if `T: OtherTrait`, use `on: Box<dyn OtherTrait>`). If the | |
| number of types you intend to feed to this method is limited, consider manually | |
| listing out the methods of different types. | |
| ### Method has no receiver | |
| Methods that do not take a `self` parameter can't be called since there won't be | |
| a way to get a pointer to the method table for them. | |
| ``` | |
| trait Foo { | |
| fn foo() -> u8; | |
| } | |
| ``` | |
| This could be called as `<Foo as Foo>::foo()`, which would not be able to pick | |
| an implementation. | |
| Adding a `Self: Sized` bound to these methods will generally make this compile. | |
| ``` | |
| trait Foo { | |
| fn foo() -> u8 where Self: Sized; | |
| } | |
| ``` | |
| ### Trait contains associated constants | |
| Just like static functions, associated constants aren't stored on the method | |
| table. If the trait or any subtrait contain an associated constant, they are not | |
| dyn compatible. | |
| ```compile_fail,E0038 | |
| trait Foo { | |
| const X: i32; | |
| } | |
| impl dyn Foo {} | |
| ``` | |
| A simple workaround is to use a helper method instead: | |
| ``` | |
| trait Foo { | |
| fn x(&self) -> i32; | |
| } | |
| ``` | |
| ### Trait uses `Self` as a type parameter in the supertrait listing | |
| This is similar to the second sub-error, but subtler. It happens in situations | |
| like the following: | |
| ```compile_fail,E0038 | |
| trait Super<A: ?Sized> {} | |
| trait Trait: Super<Self> { | |
| } | |
| struct Foo; | |
| impl Super<Foo> for Foo{} | |
| impl Trait for Foo {} | |
| fn main() { | |
| let x: Box<dyn Trait>; | |
| } | |
| ``` | |
| Here, the supertrait might have methods as follows: | |
| ``` | |
| trait Super<A: ?Sized> { | |
| fn get_a(&self) -> &A; // note that this is dyn-compatible! | |
| } | |
| ``` | |
| If the trait `Trait` was deriving from something like `Super<String>` or | |
| `Super<T>` (where `Foo` itself is `Foo<T>`), this is okay, because given a type | |
| `get_a()` will definitely return an object of that type. | |
| However, if it derives from `Super<Self>`, even though `Super` is | |
| dyn-compatible, the method `get_a()` would return an object of unknown type when | |
| called on the function. `Self` type parameters let us make dyn-compatible traits | |
| no longer compatible, so they are forbidden when specifying supertraits. | |
| There's no easy fix for this. Generally, code will need to be refactored so that | |
| you no longer need to derive from `Super<Self>`. |