Skip to content

Better document trait objects. #184

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 30, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/glossary.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,5 +137,4 @@ Generic functions and generic structs can use traits to constrain, or bound, the
[trait objects]: types.html#trait-objects
[implementations]: items/implementations.html
[traits]: items/traits.html
[object safety]: types.html#object-safety
[trait objects]: types.html#trait-objects
[object safety]: items/traits.html#object-safety
35 changes: 16 additions & 19 deletions src/items/traits.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,26 +215,18 @@ fn draw_figure<U: Shape>(surface: Surface, Figure(sh1, sh2): Figure<U>) {
}
```

## Trait objects
## Object Safety

Traits also define a [trait object] with the same name as the trait. Values of
this type are created by coercing from a pointer of some specific type to a
pointer of trait type. For example, `&T` could be coerced to `&Shape` if `T:
Shape` holds (and similarly for `Box<T>`). This coercion can either be implicit
or [explicit]. Here is an example of an explicit coercion:
Object safe traits can be the base trait of a [trait object]. A trait is
*object safe* if it has the following qualities (defined in [RFC 255]):

```rust
trait Shape { }
impl Shape for i32 { }
let mycircle = 0i32;
let myshape: Box<Shape> = Box::new(mycircle) as Box<Shape>;
```

The resulting value is a box containing the value that was cast, along with
information that identifies the methods of the implementation that was used.
Values with a trait type can have [methods called] on them, for any method in
the trait, and can be used to instantiate type parameters that are bounded by
the trait.
* It must not require `Self: Sized`
* All associated functions must either have a `where Self: Sized` bound or
* Not have any type parameters (although lifetime parameters are allowed)
* Must be a method: its first parameter must be called self, with type
`Self`, `&Self`, `&mut Self`, `Box<Self>`.
* `Self` may only be used in the type of the receiver.
* It must not have any associated constants.

## Supertraits

Expand Down Expand Up @@ -302,6 +294,11 @@ let mycircle = Box::new(mycircle) as Box<Circle>;
let nonsense = mycircle.radius() * mycircle.area();
```

[`Send`]: ../std/marker/trait.Send.html
[`Send`]: ../std/marker/trait.Sync.html
[`UnwindSafe`]: ../std/panic/trait.UnwindSafe.html
[`RefUnwindSafe`]: ../std/panic/trait.RefUnwindSafe.html
[trait object]: types.html#trait-objects
[explicit]: expressions/operator-expr.html#type-cast-expressions
[methods called]: expressions/method-call-expr.html
[methods called]: expressions/method-call-expr.html
[RFC 255]: https://github.com/rust-lang/rfcs/blob/master/text/0255-object-safety.md
85 changes: 47 additions & 38 deletions src/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,12 +146,9 @@ let slice: &[i32] = &boxed_array[..];
All elements of arrays and slices are always initialized, and access to an
array or slice is always bounds-checked in safe methods and operators.

> Note: The [`Vec<T>`] standard library type provides a heap allocated resizable
> Note: The [`Vec<T>`] standard library type provides a heap-allocated resizable
> array type.

[dynamically sized type]: dynamically-sized-types.html
[`Vec<T>`]: ../std/vec/struct.Vec.html

## Struct types

A `struct` *type* is a heterogeneous product of other types, called the
Expand All @@ -174,9 +171,8 @@ A _tuple struct_ type is just like a struct type, except that the fields are
anonymous.

A _unit-like struct_ type is like a struct type, except that it has no fields.
The one value constructed by the associated [struct
expression](expressions/struct-expr.html) is the only value that
inhabits such a type.
The one value constructed by the associated [struct expression] is the only
value that inhabits such a type.

[^structtype]: `struct` types are analogous to `struct` types in C, the
*record* types of the ML family, or the *struct* types of the Lisp family.
Expand Down Expand Up @@ -365,8 +361,8 @@ x = bo(5,7);

## Closure types

A [closure expression](expressions/closure-expr.html) produces a closure
value with a unique, anonymous type that cannot be written out.
A [closure expression] produces a closure value with a unique, anonymous type
that cannot be written out.

Depending on the requirements of the closure, its type implements one or
more of the closure traits:
Expand All @@ -387,8 +383,8 @@ more of the closure traits:
moved in the body of the closure. `Fn` inherits from `FnMut`, which itself
inherits from `FnOnce`.

Closures that don't use anything from their environment ("non capturing
closures") can be coerced to function pointers (`fn`) with the matching
Closures that don't use anything from their environment, called *non-capturing
closures*, can be coerced to function pointers (`fn`) with the matching
signature. To adopt the example from the section above:

```rust
Expand All @@ -403,10 +399,31 @@ x = bo(5,7);

## Trait objects

In Rust, trait names also refer to [dynamically sized types] called _trait
objects_. Like all <abbr title="dynamically sized types">DSTs</abbr>, trait
objects are used behind some type of pointer; for example `&SomeTrait` or
`Box<SomeTrait>`. Each instance of a pointer to a trait object includes:
A *trait object* is an opaque value of another type that implements a set of
traits. The set of traits is made up of an [object safe] *base trait* plus any
number of [auto traits].

Trait objects are written as the path to the base trait followed by the list
of auto traits all separated by `+`. For example, given a trait `Trait`, the
following are all trait objects: `Trait`, `Trait + Send`, `Trait + Send + Sync`.

Two trait object types alias each other if the base traits alias each other and
if the sets of auto traits are the same. For example,
`Trait + Send + UnwindSafe` is the same as `Trait + Unwindsafe + Send`.

> Warning: With two trait object types, even when the complete set of traits is
> the same, if the base traits differ, the type is different. For example,
> `Send + Sync` is a different type from `Sync + Send`. See [issue 33140].

> Warning: Including the same auto trait multiple times is allowed, and each
> instance is considered a unique type. As such, `Trait + Send` is a distinct
> type than `Trait + Send + Send`. See [issue 47010].

Due to the opaqueness of which concrete type the value is of, trait objects are
[dynamically sized types]. Like all
<abbr title="dynamically sized types">DSTs</abbr>, trait objects are used
behind some type of pointer; for example `&SomeTrait` or `Box<SomeTrait>`. Each
instance of a pointer to a trait object includes:

- a pointer to an instance of a type `T` that implements `SomeTrait`
- a _virtual method table_, often just called a _vtable_, which contains, for
Expand All @@ -419,23 +436,6 @@ function pointer is loaded from the trait object vtable and invoked indirectly.
The actual implementation for each vtable entry can vary on an object-by-object
basis.

Note that trait object types only exist for
<span id="object-safety">*object-safe*</span> traits ([RFC 255]):

* It must not require `Self: Sized`
* All associated functions must either have a `where Self: Sized` bound or
* Not have any type parameters (lifetime parameters are allowed)
* Must be a method: its first parameter must be called self, with type
`Self`, `&Self`, `&mut Self`, `Box<Self>`.
* `Self` may only be used in the type of the receiver.
* It must not have any associated constants.

Given a pointer-typed expression `E` of type `&T` or `Box<T>`, where `T`
implements trait `R`, casting `E` to the corresponding pointer type `&R` or
`Box<R>` results in a value of the _trait object_ `R`. This result is
represented as a pair of pointers: the vtable pointer for the `T`
implementation of `R`, and the pointer value of `E`.

An example of a trait object:

```rust
Expand All @@ -459,16 +459,18 @@ fn main() {
In this example, the trait `Printable` occurs as a trait object in both the
type signature of `print`, and the cast expression in `main`.

### Trait Object Lifetime Bounds

Since a trait object can contain references, the lifetimes of those references
need to be expressed as part of the trait object. The assumed lifetime of
references held by a trait object is called its _default object lifetime bound_.
references held by a trait object is called its *default object lifetime bound*.
These were defined in [RFC 599] and amended in [RFC 1156].

For traits that themselves have no lifetime parameters:
* If there is a unique bound from the containing type then that is the default
* If there is more than one bound from the containing type then an explicit bound must
be specified
* Otherwise the default bound is `'static`
* If there is a unique bound from the containing type then that is the default.
* If there is more than one bound from the containing type then an explicit
bound must be specified.
* Otherwise the default bound is `'static`.

```rust,ignore
// For the following trait...
Expand Down Expand Up @@ -575,7 +577,14 @@ impl Printable for String {

The notation `&self` is a shorthand for `self: &Self`.

[`Vec<T>`]: ../std/vec/struct.Vec.html
[dynamically sized type]: dynamically-sized-types.html
[dynamically sized types]: dynamically-sized-types.html
[RFC 599]: https://github.com/rust-lang/rfcs/blob/master/text/0599-default-object-bound.md
[RFC 1156]: https://github.com/rust-lang/rfcs/blob/master/text/1156-adjust-default-object-bounds.md
[RFC 255]: https://github.com/rust-lang/rfcs/blob/master/text/0255-object-safety.md
[struct expression]: expressions/struct-expr.html
[closure expression]: expressions/closure-expr.html
[auto traits]: special-types-and-traits.html#auto-traits
[object safe]: items/traits.html#object-safety
[issue 47010]: https://github.com/rust-lang/rust/issues/47010
[issue 33140]: https://github.com/rust-lang/rust/issues/33140