Skip to content

Commit bed43c4

Browse files
committed
Document how Self receiver types *actually* interact with object safety
1 parent 8c77e8b commit bed43c4

File tree

1 file changed

+31
-10
lines changed

1 file changed

+31
-10
lines changed

src/items/traits.md

+31-10
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ Object safe traits can be the base trait of a [trait object]. A trait is
7171
* `Sized` must not be a [supertrait][supertraits]. In other words, it must not require `Self: Sized`.
7272
* It must not have any associated constants.
7373
* It must not have any associated types with generics.
74-
* All associated functions must either be dispatchable from a trait object or be explicitly non-dispatchable:
74+
* All associated functions must either be dispatchable from a trait object,
75+
or be explicitly or implicitly non-dispatchable
7576
* Dispatchable functions must:
7677
* Not have any type parameters (although lifetime parameters are allowed).
7778
* Be a [method] that does not use `Self` except in the type of the receiver.
@@ -81,13 +82,26 @@ Object safe traits can be the base trait of a [trait object]. A trait is
8182
* [`Box<Self>`]
8283
* [`Rc<Self>`]
8384
* [`Arc<Self>`]
84-
* [`Pin<P>`] where `P` is one of the types above
85+
* [`Pin<P>`] where `P` is one of the types in this list (this applies recursively)
8586
* Not have an opaque return type; that is,
8687
* Not be an `async fn` (which has a hidden `Future` type).
8788
* Not have a return position `impl Trait` type (`fn example(&self) -> impl Trait`).
88-
* Not have a `where Self: Sized` bound (receiver type of `Self` (i.e. `self`) implies this).
89-
* Explicitly non-dispatchable functions require:
90-
* Have a `where Self: Sized` bound (receiver type of `Self` (i.e. `self`) implies this).
89+
* Not have a `where Self: Sized` bound.
90+
* Explicitly non-dispatchable functions must:
91+
* Have a `where Self: Sized` bound.
92+
* Implicitly non-dispatchable functions must:
93+
* Have the receiver type `Self` (i.e. `self`)
94+
* Fulfill all the conditions of dispatchable functions, except for the receiver type.
95+
96+
Methods with `Self` receiver type are implicitly non-dispatchable
97+
(“non-dispatchable” means that they cannot be called on trait object types), but
98+
[might become dispatchable in future versions of Rust](https://github.com/rust-lang/rust/issues/48055).
99+
Currently, unsized function arguments are not supported in Rust, so such methods cannot be
100+
implemented for unsized types, which means providing a function body as default implementation
101+
for the method is not possible, nor are (manual) implementations of the trait for unsized types
102+
possible. Implicitly non-dispatchable methods serve the future-compatibility of your trait,
103+
if unsized function arguments become supported in future versions of Rust,
104+
as removing an explicit `Self: Sized` bound later would constitute a semver-breaking API change.
91105

92106
```rust
93107
# use std::rc::Rc;
@@ -120,16 +134,23 @@ trait NonDispatchable {
120134
fn param(&self, other: Self) where Self: Sized {}
121135
// Generics are not compatible with vtables.
122136
fn typed<T>(&self, x: T) where Self: Sized {}
137+
// `self: Self` functions cannot be dispatched,
138+
// but this mighty change in the future
139+
fn by_value(self); // default implementation is not supported
123140
}
124141
125142
struct S;
126143
impl NonDispatchable for S {
127144
fn returns(&self) -> Self where Self: Sized { S }
145+
fn by_value(self) {}
128146
}
129147
let obj: Box<dyn NonDispatchable> = Box::new(S);
130-
obj.returns(); // ERROR: cannot call with Self return
131-
obj.param(S); // ERROR: cannot call with Self parameter
132-
obj.typed(1); // ERROR: cannot call with generic type
148+
// `dyn NonDispatchable` is a dynamically sized type
149+
// and does not implement the `Sized` trait
150+
obj.returns(); // ERROR: cannot call the function due to its `Self: Sized` bound
151+
obj.param(S); // ERROR: cannot call the function due to its `Self: Sized` bound
152+
obj.typed(1); // ERROR: cannot call the function due to its `Self: Sized` bound
153+
obj.by_value(); // ERROR: cannot call functions with dynamically sized arguments
133154
```
134155

135156
```rust,compile_fail
@@ -162,8 +183,8 @@ let obj: Box<dyn TraitWithSize> = Box::new(S); // ERROR
162183

163184
```rust,compile_fail
164185
// Not object safe if `Self` is a type argument.
165-
trait Super<A> {}
166-
trait WithSelf: Super<Self> where Self: Sized {}
186+
trait Super<A: ?Sized> {}
187+
trait WithSelf: Super<Self> {}
167188
168189
struct S;
169190
impl<A> Super<A> for S {}

0 commit comments

Comments
 (0)