1- Trait objects like ` Box<Trait> ` can only be constructed when certain
2- requirements are satisfied by the trait in question.
3-
4- Trait objects are a form of dynamic dispatch and use a dynamically sized type
5- for the inner type. So, for a given trait ` Trait ` , when ` Trait ` is treated as a
6- type, as in ` Box<Trait> ` , the inner type is 'unsized'. In such cases the boxed
7- pointer is a 'fat pointer' that contains an extra pointer to a table of methods
8- (among other things) for dynamic dispatch. This design mandates some
9- restrictions on the types of traits that are allowed to be used in trait
10- objects, which are collectively termed as 'object safety' rules.
11-
12- Attempting to create a trait object for a non object-safe trait will trigger
13- this error.
14-
15- There are various rules:
16-
17- ### The trait cannot require ` Self: Sized `
18-
19- When ` Trait ` is treated as a type, the type does not implement the special
20- ` Sized ` trait, because the type does not have a known size at compile time and
21- can only be accessed behind a pointer. Thus, if we have a trait like the
22- following:
1+ For any given trait ` Trait ` there may be a related _ type_ called the _ trait
2+ object type_ which is typically written as ` dyn Trait ` . In earlier editions of
3+ Rust, trait object types were written as plain ` Trait ` (just the name of the
4+ trait, written in type positions) but this was a bit too confusing, so we now
5+ write ` dyn Trait ` .
6+
7+ Some traits are not allowed to be used as trait object types. The traits that
8+ are allowed to be used as trait object types are called "object-safe" traits.
9+ Attempting to use a trait object type for a trait that is not object-safe will
10+ trigger error E0038.
11+
12+ Two general aspects of trait object types give rise to the restrictions:
13+
14+ 1 . Trait object types are dynamically sized types (DSTs), and trait objects of
15+ these types can only be accessed through pointers, such as ` &dyn Trait ` or
16+ ` Box<dyn Trait> ` . The size of such a pointer is known, but the size of the
17+ ` dyn Trait ` object pointed-to by the pointer is _ opaque_ to code working
18+ with it, and different tait objects with the same trait object type may
19+ have different sizes.
20+
21+ 2 . The pointer used to access a trait object is paired with an extra pointer
22+ to a "virtual method table" or "vtable", which is used to implement dynamic
23+ dispatch to the object's implementations of the trait's methods. There is a
24+ single such vtable for each trait implementation, but different trait
25+ objects with the same trait object type may point to vtables from different
26+ implementations.
27+
28+ The specific conditions that violate object-safety follow, most of which relate
29+ to missing size information and vtable polymorphism arising from these aspects.
30+
31+ ### The trait requires ` Self: Sized `
32+
33+ Traits that are declared as ` Trait: Sized ` or which otherwise inherit a
34+ constraint of ` Self:Sized ` are not object-safe.
35+
36+ The reasoning behind this is somewhat subtle. It derives from the fact that Rust
37+ requires (and defines) that every trait object type ` dyn Trait ` automatically
38+ implements ` Trait ` . Rust does this to simplify error reporting and ease
39+ interoperation between static and dynamic polymorphism. For example, this code
40+ works:
2341
2442```
25- trait Foo where Self: Sized {
43+ trait Trait {
44+ }
45+
46+ fn static_foo<T:Trait + ?Sized>(b: &T) {
47+ }
2648
49+ fn dynamic_bar(a: &dyn Trait) {
50+ static_foo(a)
2751}
2852```
2953
30- We cannot create an object of type ` Box<Foo> ` or ` &Foo ` since in this case
31- ` Self ` would not be ` Sized ` .
54+ This code works because ` dyn Trait ` , if it exists, always implements ` Trait ` .
55+
56+ However as we know, any ` dyn Trait ` is also unsized, and so it can never
57+ implement a sized trait like ` Trait:Sized ` . So, rather than allow an exception
58+ to the rule that ` dyn Trait ` always implements ` Trait ` , Rust chooses to prohibit
59+ such a ` dyn Trait ` from existing at all.
60+
61+ Only unsized traits are considered object-safe.
3262
3363Generally, ` Self: Sized ` is used to indicate that the trait should not be used
3464as a trait object. If the trait comes from your own crate, consider removing
@@ -67,7 +97,7 @@ trait Trait {
6797 fn foo(&self) -> Self;
6898}
6999
70- fn call_foo(x: Box<Trait>) {
100+ fn call_foo(x: Box<dyn Trait>) {
71101 let y = x.foo(); // What type is y?
72102 // ...
73103}
@@ -76,7 +106,8 @@ fn call_foo(x: Box<Trait>) {
76106If only some methods aren't object-safe, you can add a ` where Self: Sized ` bound
77107on them to mark them as explicitly unavailable to trait objects. The
78108functionality will still be available to all other implementers, including
79- ` Box<Trait> ` which is itself sized (assuming you ` impl Trait for Box<Trait> ` ).
109+ ` Box<dyn Trait> ` which is itself sized (assuming you `impl Trait for Box<dyn
110+ Trait>`).
80111
81112```
82113trait Trait {
@@ -115,7 +146,9 @@ impl Trait for u8 {
115146```
116147
117148At compile time each implementation of ` Trait ` will produce a table containing
118- the various methods (and other items) related to the implementation.
149+ the various methods (and other items) related to the implementation, which will
150+ be used as the virtual method table for a ` dyn Trait ` object derived from that
151+ implementation.
119152
120153This works fine, but when the method gains generic parameters, we can have a
121154problem.
@@ -174,7 +207,7 @@ Now, if we have the following code:
174207# impl Trait for u8 { fn foo<T>(&self, on: T) {} }
175208# impl Trait for bool { fn foo<T>(&self, on: T) {} }
176209# // etc.
177- fn call_foo(thing: Box<Trait>) {
210+ fn call_foo(thing: Box<dyn Trait>) {
178211 thing.foo(true); // this could be any one of the 8 types above
179212 thing.foo(1);
180213 thing.foo("hello");
@@ -200,7 +233,7 @@ trait Trait {
200233```
201234
202235If this is not an option, consider replacing the type parameter with another
203- trait object (e.g., if ` T: OtherTrait ` , use ` on: Box<OtherTrait> ` ). If the
236+ trait object (e.g., if ` T: OtherTrait ` , use ` on: Box<dyn OtherTrait> ` ). If the
204237number of types you intend to feed to this method is limited, consider manually
205238listing out the methods of different types.
206239
@@ -226,7 +259,7 @@ trait Foo {
226259}
227260```
228261
229- ### The trait cannot contain associated constants
262+ ### Trait contains associated constants
230263
231264Just like static functions, associated constants aren't stored on the method
232265table. If the trait or any subtrait contain an associated constant, they cannot
@@ -248,7 +281,7 @@ trait Foo {
248281}
249282```
250283
251- ### The trait cannot use ` Self ` as a type parameter in the supertrait listing
284+ ### Trait uses ` Self ` as a type parameter in the supertrait listing
252285
253286This is similar to the second sub-error, but subtler. It happens in situations
254287like the following:
0 commit comments