Skip to content

Commit b09e52c

Browse files
committed
Improve wording and examples about supertraits
1 parent 0489584 commit b09e52c

File tree

2 files changed

+41
-37
lines changed

2 files changed

+41
-37
lines changed

src/items/traits.md

Lines changed: 37 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ interface consists of [associated items], which come in three varieties:
1010
All traits define an implicit type parameter `Self` that refers to "the type
1111
that is implementing this interface". Traits may also contain additional type
1212
parameters. These type parameters (including `Self`) may be constrained by
13-
other traits and so forth as usual.
13+
other traits and so forth [as usual].
1414

1515
Traits are implemented for specific types through separate [implementations].
1616

@@ -48,71 +48,72 @@ Object safe traits can be the base trait of a [trait object]. A trait is
4848
and
4949
* Be a [method] that does not use `Self` except in the type of the receiver.
5050
* It must not have any associated constants.
51+
* All supertraits must also be object safe.
5152

5253
## Supertraits
5354

54-
Trait bounds on `Self` are considered "supertraits". These are required to be
55-
acyclic. Supertraits are somewhat different from other constraints in that
56-
they affect what methods are available in the vtable when the trait is used as
57-
a [trait object]. Consider the following example:
55+
**Supertraits** are traits that are required to be implemented for a type to
56+
implement a specific trait. Furthermore, anywhere a [generic] or [trait object]
57+
is bounded by a trait, it has access to the associated items of its supertraits.
58+
59+
Supertraits are declared by trait bounds on the `Self` type of a trait and
60+
transitively the supertraits of the traits declared in those trait bounds. It is
61+
an error for a trait to be its own supertrait.
62+
63+
The following is an example of declaring `Shape` to be a supertrait of `Circle`.
5864

5965
```rust
6066
trait Shape { fn area(&self) -> f64; }
6167
trait Circle : Shape { fn radius(&self) -> f64; }
6268
```
6369

64-
The syntax `Circle : Shape` means that types that implement `Circle` must also
65-
have an implementation for `Shape`. Multiple supertraits are separated by `+`,
66-
`trait Circle : Shape + PartialEq { }`. In an implementation of `Circle` for a
67-
given type `T`, methods can refer to `Shape` methods, since the typechecker
68-
checks that any type with an implementation of `Circle` also has an
69-
implementation of `Shape`:
70+
And the following is the same example, except using [where clauses].
7071

7172
```rust
72-
struct Foo;
73-
7473
trait Shape { fn area(&self) -> f64; }
75-
trait Circle : Shape { fn radius(&self) -> f64; }
76-
impl Shape for Foo {
77-
fn area(&self) -> f64 {
78-
0.0
79-
}
80-
}
81-
impl Circle for Foo {
82-
fn radius(&self) -> f64 {
83-
println!("calling area: {}", self.area());
74+
trait Circle where Self: Shape { fn radius(&self) -> f64; }
75+
```
76+
77+
This next example gives `radius` a default implementation using the `area`
78+
function from `Shape`.
8479

85-
0.0
80+
```rust
81+
# trait Shape { fn area(&self) -> f64; }
82+
trait Circle where Self: Shape {
83+
fn radius(&self) -> f64 {
84+
// A = pi * r^2
85+
// so algebraically,
86+
// r = sqrt(A / pi)
87+
(self.area() /std::f64::consts::PI).sqrt()
8688
}
8789
}
88-
89-
let c = Foo;
90-
c.radius();
9190
```
9291

9392
In type-parameterized functions, methods of the supertrait may be called on
94-
values of subtrait-bound type parameters. Referring to the previous example of
93+
values of subtrait-bound type parameters. Continuing the example of
9594
`trait Circle : Shape`:
9695

9796
```rust
9897
# trait Shape { fn area(&self) -> f64; }
9998
# trait Circle : Shape { fn radius(&self) -> f64; }
100-
fn radius_times_area<T: Circle>(c: T) -> f64 {
101-
// `c` is both a Circle and a Shape
102-
c.radius() * c.area()
99+
fn print_area_and_radius<C: Circle>(c: C) {
100+
// Here we call the area method from the supertrait `Shape` of `Circle`.
101+
println!("Area: {}", c.area());
102+
println!("Radius: {}", c.radius());
103103
}
104104
```
105105

106-
Likewise, supertrait methods may also be called on trait objects.
106+
Likewise, here is an example of calling supertrait methods on trait objects.
107107

108108
```rust
109109
# trait Shape { fn area(&self) -> f64; }
110110
# trait Circle : Shape { fn radius(&self) -> f64; }
111+
# struct UnitCircle;
111112
# impl Shape for i32 { fn area(&self) -> f64 { 0.0 } }
112113
# impl Circle for i32 { fn radius(&self) -> f64 { 0.0 } }
113114
# let mycircle = 0i32;
114-
let mycircle = Box::new(mycircle) as Box<Circle>;
115-
let nonsense = mycircle.radius() * mycircle.area();
115+
let circle = Box::new(mycircle) as Box<dyn Circle>;
116+
let nonsense = circle.radius() * circle.area();
116117
```
117118

118119
[bounds]: trait-bounds.html
@@ -121,4 +122,6 @@ let nonsense = mycircle.radius() * mycircle.area();
121122
[RFC 255]: https://github.com/rust-lang/rfcs/blob/master/text/0255-object-safety.md
122123
[associated items]: items/associated-items.html
123124
[method]: items/associated-items.html#methods
124-
[implementations]: items/implementations.html
125+
[implementations]: items/implementations.html
126+
[as usual]: items/generics.html
127+
[where clauses]: items/generics.html#where-clauses

src/types.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ A *trait object* is an opaque value of another type that implements a set of
545545
traits. The set of traits is made up of an [object safe] *base trait* plus any
546546
number of [auto traits].
547547

548-
Trait objects implement the base trait, its auto traits, and any super traits
548+
Trait objects implement the base trait, its auto traits, and any [supertraits]
549549
of the base trait.
550550

551551
Trait objects are written as the optional keyword `dyn` followed by a set of
@@ -597,8 +597,8 @@ behind some type of pointer; for example `&dyn SomeTrait` or
597597

598598
- a pointer to an instance of a type `T` that implements `SomeTrait`
599599
- a _virtual method table_, often just called a _vtable_, which contains, for
600-
each method of `SomeTrait` that `T` implements, a pointer to `T`'s
601-
implementation (i.e. a function pointer).
600+
each method of `SomeTrait` and its [supertraits] that `T` implements, a
601+
pointer to `T`'s implementation (i.e. a function pointer).
602602

603603
The purpose of trait objects is to permit "late binding" of methods. Calling a
604604
method on a trait object results in virtual dispatch at runtime: that is, a
@@ -712,3 +712,4 @@ impl Printable for String {
712712
[issue 33140]: https://github.com/rust-lang/rust/issues/33140
713713
[_PATH_]: paths.html
714714
[_LIFETIME_OR_LABEL_]: tokens.html#lifetimes-and-loop-labels
715+
[supertraits]: items/traits.html#supertraits

0 commit comments

Comments
 (0)