Skip to content

Commit aeb9d4c

Browse files
conradludgateehuss
authored andcommitted
address some comments
1 parent 510938c commit aeb9d4c

File tree

1 file changed

+23
-16
lines changed

1 file changed

+23
-16
lines changed

src/subtyping.md

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ while also preventing their misuse, Rust uses a combination of **Subtyping** and
99

1010
## Subtyping
1111

12-
Subtyping is the idea that one type can be a *subtype* of another.
12+
Subtyping is the idea that one type can be used in place of another.
1313

1414
Let's define that `Sub` is a subtype of `Super` (we'll be using the notation `Sub: Super` throughout this chapter)
1515

@@ -21,15 +21,15 @@ An example of simple subtyping that exists in the language are [supertraits](htt
2121
```rust
2222
use std::fmt;
2323

24-
trait OutlinePrint: fmt::Display {
25-
fn outline_print(&self) {
26-
todo!()
27-
}
24+
pub trait Error: fmt::Display {
25+
fn source(&self) -> Option<&(dyn Error + 'static)>;
26+
fn description(&self) -> &str;
27+
fn cause(&self) -> Option<&dyn Error>;
2828
}
2929
```
3030

31-
Here, we have that `OutlinePrint: fmt::Display` (`OutlinePrint` is a *subtype* of `Display`),
32-
because it has all the requirements of `fmt::Display`, plus the `outline_print` function.
31+
Here, we have that `Error: fmt::Display` (`Error` is a *subtype* of `Display`),
32+
because it has all the requirements of `fmt::Display`, plus the `source`/`description`/`cause` functions.
3333

3434
However, subtyping in traits is not that interesting in the case of Rust.
3535
Here in the nomicon, we're going to focus more with how subtyping interacts with **lifetimes**
@@ -51,7 +51,7 @@ fn main() {
5151
}
5252
```
5353

54-
In an overly restrictive implementation of lifetimes, since `a` and `b` have differeing lifetimes,
54+
In a conservative implementation of lifetimes, since `a` and `b` have differeing lifetimes,
5555
we might see the following error:
5656

5757
```text
@@ -64,10 +64,12 @@ error[E0308]: mismatched types
6464
| expected `&'static str`, found struct `&'b str`
6565
```
6666

67-
This is over-restrictive. In this case, what we want is to accept any type that lives *at least as long* as `'b`.
67+
This would be rather unfortunate. In this case,
68+
what we want is to accept any type that lives *at least as long* as `'b`.
6869
Let's try using subtyping with our lifetimes.
6970

70-
Let's define a lifetime to have the a simple set of requirements: `'a` defines a region of code in which a value will be alive.
71+
Let's define a lifetime to have the a simple set of requirements:
72+
`'a` defines a region of code in which a value will be alive.
7173
Now that we have a defined set of requirements for lifetimes, we can define how they relate to each other.
7274
`'a: 'b` if and only if `'a` defines a region of code that **completely contains** `'b`.
7375

@@ -108,20 +110,24 @@ fn main() {
108110
let world = String::from("world");
109111
assign(&mut hello, &world);
110112
}
113+
println!("{}", hello);
111114
}
112115
```
113116

114-
If this were to compile, this would have a memory bug.
117+
In `assign`, we are setting the `hello` reference to point to `world`.
118+
But then `world` goes out of scope, before the later use of `hello` in the println!
119+
120+
This is a classic use-after-free bug!
115121

116-
If we were to expand this out, we'd see that we're trying to assign a `&'b str` into a `&'static str`,
117-
but the problem is that as soon as `b` goes out of scope, `a` is now invalid, even though it's supposed to have a `'static` lifetime.
122+
Our first instinct might be to blame the `assign` impl, but there's really nothing wrong here.
123+
It shouldn't be surprising that we might want to assign a `T` into a `T`.
118124

119-
However, the implementation of `assign` is valid.
120-
Therefore, this must mean that `&mut &'static str` should **not** a *subtype* of `&mut &'b str`,
125+
The problem is that we cannot assume that `&mut &'static str` and `&mut &'b str` are compatible.
126+
This must mean that `&mut &'static str` should **not** be a *subtype* of `&mut &'b str`,
121127
even if `'static` is a subtype of `'b`.
122128

123129
Variance is the way that Rust defines the relationships of subtypes through their *type constructor*.
124-
A type constructor in Rust is any generic type with unbound arguments.
130+
A type constructor is any generic type with unbound arguments.
125131
For instance `Vec` is a type constructor that takes a type `T` and returns
126132
`Vec<T>`. `&` and `&mut` are type constructors that take two inputs: a
127133
lifetime, and a type to point to.
@@ -190,6 +196,7 @@ fn main() {
190196
let world = String::from("world");
191197
assign(&mut hello, &world);
192198
}
199+
println!("{}", hello);
193200
}
194201
```
195202

0 commit comments

Comments
 (0)