1 Trait objects like `Box<Trait>` can only be constructed when certain
2 requirements are satisfied by the trait in question.
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.
12 Attempting to create a trait object for a non object-safe trait will trigger
15 There are various rules:
17 ### The trait cannot require `Self: Sized`
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
25 trait Foo where Self: Sized {
30 We cannot create an object of type `Box<Foo>` or `&Foo` since in this case
31 `Self` would not be `Sized`.
33 Generally, `Self: Sized` is used to indicate that the trait should not be used
34 as a trait object. If the trait comes from your own crate, consider removing
37 ### Method references the `Self` type in its parameters or return type
39 This happens when a trait has a method like the following:
43 fn foo(&self) -> Self;
46 impl Trait for String {
47 fn foo(&self) -> Self {
53 fn foo(&self) -> Self {
59 (Note that `&self` and `&mut self` are okay, it's additional `Self` types which
62 In such a case, the compiler cannot predict the return type of `foo()` in a
63 situation like the following:
67 fn foo(&self) -> Self;
70 fn call_foo(x: Box<Trait>) {
71 let y = x.foo(); // What type is y?
76 If only some methods aren't object-safe, you can add a `where Self: Sized` bound
77 on them to mark them as explicitly unavailable to trait objects. The
78 functionality will still be available to all other implementers, including
79 `Box<Trait>` which is itself sized (assuming you `impl Trait for Box<Trait>`).
83 fn foo(&self) -> Self where Self: Sized;
88 Now, `foo()` can no longer be called on a trait object, but you will now be
89 allowed to make a trait object, and that will be able to call any object-safe
90 methods. With such a bound, one can still call `foo()` on types implementing
91 that trait that aren't behind trait objects.
93 ### Method has generic type parameters
95 As mentioned before, trait objects contain pointers to method tables. So, if we
103 impl Trait for String {
117 At compile time each implementation of `Trait` will produce a table containing
118 the various methods (and other items) related to the implementation.
120 This works fine, but when the method gains generic parameters, we can have a
123 Usually, generic parameters get _monomorphized_. For example, if I have
131 The machine code for `foo::<u8>()`, `foo::<bool>()`, `foo::<String>()`, or any
132 other type substitution is different. Hence the compiler generates the
133 implementation on-demand. If you call `foo()` with a `bool` parameter, the
134 compiler will only generate code for `foo::<bool>()`. When we have additional
135 type parameters, the number of monomorphized implementations the compiler
136 generates does not grow drastically, since the compiler will only generate an
137 implementation if the function is called with unparametrized substitutions
138 (i.e., substitutions where none of the substituted types are themselves
141 However, with trait objects we have to make a table containing _every_ object
142 that implements the trait. Now, if it has type parameters, we need to add
143 implementations for every type that implements the trait, and there could
144 theoretically be an infinite number of types.
150 fn foo<T>(&self, on: T);
154 impl Trait for String {
155 fn foo<T>(&self, on: T) {
161 fn foo<T>(&self, on: T) {
166 // 8 more implementations
169 Now, if we have the following code:
171 ```compile_fail,E0038
172 # trait Trait { fn foo<T>(&self, on: T); }
173 # impl Trait for String { fn foo<T>(&self, on: T) {} }
174 # impl Trait for u8 { fn foo<T>(&self, on: T) {} }
175 # impl Trait for bool { fn foo<T>(&self, on: T) {} }
177 fn call_foo(thing: Box<Trait>) {
178 thing.foo(true); // this could be any one of the 8 types above
184 We don't just need to create a table of all implementations of all methods of
185 `Trait`, we need to create such a table, for each different type fed to
186 `foo()`. In this case this turns out to be (10 types implementing `Trait`)\*(3
187 types being fed to `foo()`) = 30 implementations!
189 With real world traits these numbers can grow drastically.
191 To fix this, it is suggested to use a `where Self: Sized` bound similar to the
192 fix for the sub-error above if you do not intend to call the method with type
197 fn foo<T>(&self, on: T) where Self: Sized;
202 If 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
204 number of types you intend to feed to this method is limited, consider manually
205 listing out the methods of different types.
207 ### Method has no receiver
209 Methods that do not take a `self` parameter can't be called since there won't be
210 a way to get a pointer to the method table for them.
218 This could be called as `<Foo as Foo>::foo()`, which would not be able to pick
221 Adding a `Self: Sized` bound to these methods will generally make this compile.
225 fn foo() -> u8 where Self: Sized;
229 ### The trait cannot contain associated constants
231 Just like static functions, associated constants aren't stored on the method
232 table. If the trait or any subtrait contain an associated constant, they cannot
233 be made into an object.
235 ```compile_fail,E0038
243 A simple workaround is to use a helper method instead:
251 ### The trait cannot use `Self` as a type parameter in the supertrait listing
253 This is similar to the second sub-error, but subtler. It happens in situations
256 ```compile_fail,E0038
257 trait Super<A: ?Sized> {}
259 trait Trait: Super<Self> {
264 impl Super<Foo> for Foo{}
266 impl Trait for Foo {}
269 let x: Box<dyn Trait>;
273 Here, the supertrait might have methods as follows:
276 trait Super<A: ?Sized> {
277 fn get_a(&self) -> &A; // note that this is object safe!
281 If the trait `Trait` was deriving from something like `Super<String>` or
282 `Super<T>` (where `Foo` itself is `Foo<T>`), this is okay, because given a type
283 `get_a()` will definitely return an object of that type.
285 However, if it derives from `Super<Self>`, even though `Super` is object safe,
286 the method `get_a()` would return an object of unknown type when called on the
287 function. `Self` type parameters let us make object safe traits no longer safe,
288 so they are forbidden when specifying supertraits.
290 There's no easy fix for this. Generally, code will need to be refactored so that
291 you no longer need to derive from `Super<Self>`.