Skip to content

Commit 1d791b5

Browse files
authored
Merge pull request #184 from Havvy/trait-objects
Better document trait objects.
2 parents 6871424 + ea1c7f5 commit 1d791b5

File tree

3 files changed

+64
-59
lines changed

3 files changed

+64
-59
lines changed

src/glossary.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -137,5 +137,4 @@ Generic functions and generic structs can use traits to constrain, or bound, the
137137
[trait objects]: types.html#trait-objects
138138
[implementations]: items/implementations.html
139139
[traits]: items/traits.html
140-
[object safety]: types.html#object-safety
141-
[trait objects]: types.html#trait-objects
140+
[object safety]: items/traits.html#object-safety

src/items/traits.md

+16-19
Original file line numberDiff line numberDiff line change
@@ -215,26 +215,18 @@ fn draw_figure<U: Shape>(surface: Surface, Figure(sh1, sh2): Figure<U>) {
215215
}
216216
```
217217

218-
## Trait objects
218+
## Object Safety
219219

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

226-
```rust
227-
trait Shape { }
228-
impl Shape for i32 { }
229-
let mycircle = 0i32;
230-
let myshape: Box<Shape> = Box::new(mycircle) as Box<Shape>;
231-
```
232-
233-
The resulting value is a box containing the value that was cast, along with
234-
information that identifies the methods of the implementation that was used.
235-
Values with a trait type can have [methods called] on them, for any method in
236-
the trait, and can be used to instantiate type parameters that are bounded by
237-
the trait.
223+
* It must not require `Self: Sized`
224+
* All associated functions must either have a `where Self: Sized` bound or
225+
* Not have any type parameters (although lifetime parameters are allowed)
226+
* Must be a method: its first parameter must be called self, with type
227+
`Self`, `&Self`, `&mut Self`, `Box<Self>`.
228+
* `Self` may only be used in the type of the receiver.
229+
* It must not have any associated constants.
238230

239231
## Supertraits
240232

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

297+
[`Send`]: ../std/marker/trait.Send.html
298+
[`Send`]: ../std/marker/trait.Sync.html
299+
[`UnwindSafe`]: ../std/panic/trait.UnwindSafe.html
300+
[`RefUnwindSafe`]: ../std/panic/trait.RefUnwindSafe.html
305301
[trait object]: types.html#trait-objects
306302
[explicit]: expressions/operator-expr.html#type-cast-expressions
307-
[methods called]: expressions/method-call-expr.html
303+
[methods called]: expressions/method-call-expr.html
304+
[RFC 255]: https://github.com/rust-lang/rfcs/blob/master/text/0255-object-safety.md

src/types.md

+47-38
Original file line numberDiff line numberDiff line change
@@ -146,12 +146,9 @@ let slice: &[i32] = &boxed_array[..];
146146
All elements of arrays and slices are always initialized, and access to an
147147
array or slice is always bounds-checked in safe methods and operators.
148148

149-
> Note: The [`Vec<T>`] standard library type provides a heap allocated resizable
149+
> Note: The [`Vec<T>`] standard library type provides a heap-allocated resizable
150150
> array type.
151151
152-
[dynamically sized type]: dynamically-sized-types.html
153-
[`Vec<T>`]: ../std/vec/struct.Vec.html
154-
155152
## Struct types
156153

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

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

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

366362
## Closure types
367363

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

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

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

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

404400
## Trait objects
405401

406-
In Rust, trait names also refer to [dynamically sized types] called _trait
407-
objects_. Like all <abbr title="dynamically sized types">DSTs</abbr>, trait
408-
objects are used behind some type of pointer; for example `&SomeTrait` or
409-
`Box<SomeTrait>`. Each instance of a pointer to a trait object includes:
402+
A *trait object* is an opaque value of another type that implements a set of
403+
traits. The set of traits is made up of an [object safe] *base trait* plus any
404+
number of [auto traits].
405+
406+
Trait objects are written as the path to the base trait followed by the list
407+
of auto traits all separated by `+`. For example, given a trait `Trait`, the
408+
following are all trait objects: `Trait`, `Trait + Send`, `Trait + Send + Sync`.
409+
410+
Two trait object types alias each other if the base traits alias each other and
411+
if the sets of auto traits are the same. For example,
412+
`Trait + Send + UnwindSafe` is the same as `Trait + Unwindsafe + Send`.
413+
414+
> Warning: With two trait object types, even when the complete set of traits is
415+
> the same, if the base traits differ, the type is different. For example,
416+
> `Send + Sync` is a different type from `Sync + Send`. See [issue 33140].
417+
418+
> Warning: Including the same auto trait multiple times is allowed, and each
419+
> instance is considered a unique type. As such, `Trait + Send` is a distinct
420+
> type than `Trait + Send + Send`. See [issue 47010].
421+
422+
Due to the opaqueness of which concrete type the value is of, trait objects are
423+
[dynamically sized types]. Like all
424+
<abbr title="dynamically sized types">DSTs</abbr>, trait objects are used
425+
behind some type of pointer; for example `&SomeTrait` or `Box<SomeTrait>`. Each
426+
instance of a pointer to a trait object includes:
410427

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

422-
Note that trait object types only exist for
423-
<span id="object-safety">*object-safe*</span> traits ([RFC 255]):
424-
425-
* It must not require `Self: Sized`
426-
* All associated functions must either have a `where Self: Sized` bound or
427-
* Not have any type parameters (lifetime parameters are allowed)
428-
* Must be a method: its first parameter must be called self, with type
429-
`Self`, `&Self`, `&mut Self`, `Box<Self>`.
430-
* `Self` may only be used in the type of the receiver.
431-
* It must not have any associated constants.
432-
433-
Given a pointer-typed expression `E` of type `&T` or `Box<T>`, where `T`
434-
implements trait `R`, casting `E` to the corresponding pointer type `&R` or
435-
`Box<R>` results in a value of the _trait object_ `R`. This result is
436-
represented as a pair of pointers: the vtable pointer for the `T`
437-
implementation of `R`, and the pointer value of `E`.
438-
439439
An example of a trait object:
440440

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

462+
### Trait Object Lifetime Bounds
463+
462464
Since a trait object can contain references, the lifetimes of those references
463465
need to be expressed as part of the trait object. The assumed lifetime of
464-
references held by a trait object is called its _default object lifetime bound_.
466+
references held by a trait object is called its *default object lifetime bound*.
465467
These were defined in [RFC 599] and amended in [RFC 1156].
466468

467469
For traits that themselves have no lifetime parameters:
468-
* If there is a unique bound from the containing type then that is the default
469-
* If there is more than one bound from the containing type then an explicit bound must
470-
be specified
471-
* Otherwise the default bound is `'static`
470+
* If there is a unique bound from the containing type then that is the default.
471+
* If there is more than one bound from the containing type then an explicit
472+
bound must be specified.
473+
* Otherwise the default bound is `'static`.
472474

473475
```rust,ignore
474476
// For the following trait...
@@ -575,7 +577,14 @@ impl Printable for String {
575577

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

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

0 commit comments

Comments
 (0)