Skip to content

Commit

Permalink
Add elaboration of object-safe receivers.
Browse files Browse the repository at this point in the history
  • Loading branch information
ehuss committed Dec 4, 2019
1 parent 68e4157 commit af6c31b
Showing 1 changed file with 97 additions and 0 deletions.
97 changes: 97 additions & 0 deletions src/items/traits.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,99 @@ Object safe traits can be the base trait of a [trait object]. A trait is
* It must not have any associated constants.
* All supertraits must also be object safe.

When there isn't a `Self: Sized` bound on a method, the type of a method
receiver must be one of the following types:

* `&Self`
* `&mut Self`
* [`Box<Self>`]
* [`Rc<Self>`]
* [`Arc<Self>`]
* [`Pin<P>`] where `P` is one of the object safe receiver types

```rust
# use std::rc::Rc;
# use std::sync::Arc;
# use std::pin::Pin;
// Examples of object safe methods.
trait TraitMethods {
fn by_ref(self: &Self) {}
fn by_ref_mut(self: &mut Self) {}
fn by_box(self: Box<Self>) {}
fn by_rc(self: Rc<Self>) {}
fn by_arc(self: Arc<Self>) {}
fn by_pin(self: Pin<&Self>) {}
fn with_lifetime<'a>(self: &'a Self) {}
fn nested_pin(self: Pin<Arc<Self>>) {}
}
# struct S;
# impl TraitMethods for S {}
# let t: Box<dyn TraitMethods> = Box::new(S);
```

```rust,compile_fail
// These are object-safe, but cannot be dispatched on a trait object.
trait NonDispatchable {
// Non-methods cannot be dispatched.
fn foo() where Self: Sized {}
// Self type isn't known until runtime.
fn returns(&self) -> Self where Self: Sized;
// `other` may be a different concrete type of the receiver.
fn param(&self, other: Self) where Self: Sized {}
// Generics are not compatible with vtables.
// Alternate solution is to use a trait object instead.
fn typed<T>(&self, x: T) where Self: Sized {}
}
struct S;
impl NonDispatchable for S {
fn returns(&self) -> Self where Self: Sized { S }
}
let obj: Box<dyn NonDispatchable> = Box::new(S);
obj.returns(); // ERROR: cannot call with Self return
obj.param(S); // ERROR: cannot call with Self parameter
obj.typed(1); // ERROR: cannot call with generic type
```

```rust,compile_fail
# use std::rc::Rc;
// Examples of non-object safe traits.
trait NotObjectSafe {
const CONST: i32 = 1; // ERROR: cannot have associated const
fn foo() {} // ERROR: associated function without Sized
fn returns(&self) -> Self; // ERROR: Self in return type
fn typed<T>(&self, x: T) {} // ERROR: has generic type parameters
fn nested(self: Rc<Box<Self>>) {} // ERROR: nested receiver not yet supported
}
struct S;
impl NotObjectSafe for S {
fn returns(&self) -> Self { S }
}
let obj: Box<dyn NotObjectSafe> = Box::new(S); // ERROR
```

```rust,compile_fail
// Self: Sized traits are not object-safe.
trait TraitWithSize where Self: Sized {}
struct S;
impl TraitWithSize for S {}
let obj: Box<dyn TraitWithSize> = Box::new(S); // ERROR
```

```rust,compile_fail
// Not object safe if `Self` is a type parameter.
trait Super<A> {}
trait WithSelf: Super<Self> where Self: Sized {}
struct S;
impl<A> Super<A> for S {}
impl WithSelf for S {}
let obj: Box<dyn WithSelf> = Box::new(S); // ERROR: cannot use `Self` type parameter
```

## Supertraits

**Supertraits** are traits that are required to be implemented for a type to
Expand Down Expand Up @@ -231,3 +324,7 @@ trait T {
[trait implementation]: implementations.md#trait-implementations
[`Send`]: ../special-types-and-traits.md#send
[`Sync`]: ../special-types-and-traits.md#sync
[`Arc<Self>`]: ../special-types-and-traits.md#arct
[`Box<Self>`]: ../special-types-and-traits.md#boxt
[`Pin<P>`]: ../special-types-and-traits.md#pinp
[`Rc<Self>`]: ../special-types-and-traits.md#rct

0 comments on commit af6c31b

Please sign in to comment.