The idea is that `shortest()` returns a reference to the shorter of the two
`print_shortest()` has been renamed to `shortest()`, which instead of printing,
strings referenced by its arguments, but *without* allocating a new string.
now returns the shorter of the two strings. It does this using only references
Let's de-sugar `main()` so we can see the implicit lifetimes:
for efficiency, avoiding the need to re-allocate a new string to pass back to
`main()`. The responsibility of printing the result has been shifted to `main()`.
Let's again de-sugar `main()` by adding explicit scopes and lifetimes:
```rust,ignore
```rust,ignore
fn main() {
fn main() {
'a {
's1 {
let s1 = String::from("short");
let s1 = String::from("short");
b' {
'res {
let s2r: &'b = &'b String::from("a long long long string");
let res: &'res str;
'c {
's2 {
// Annonymous scope for the borrow of s1
let s2 = String::from("a long long long string");
println!("{}", shortest(&'c s1, s2r));
res: &'res: str = shortest(&'s1 s1, &'s2 s2);
println!("{}", res);
}
}
}
}
}
}
}
}
```
```
Now we see that the references passed as arguments to `shortest()`, i.e. `&s1`
Again, at the call-site of `shortest()` the comipiler needs to check the
and `&s2`, actually have different lifetimes (`&'b` and `&'c` respectively), since the borrows occur in different scopes.
consistency of the arguments in the caller with the signature of the callee.
However, the signature of
The signature of `shortest()` fisrt says that the two reference arguments have
`shortest()` requires that these two references (and also the returned
the same lifetime, which can be prove ok in the same way as before, thus giving
reference, which has lifetime `'c`) have the same lifetime. So how does the
us:
compiler make sure this is the case?
At the call-site of `shortest()`, the compiler must try to *convert* the lifetimes of
```rust,ignore
the references marked `&'a` in the signature of `shortest()`
res: &'res = shortest(&'s2 s1, &'s2 s2);
into a single compatible lifetime. This new lifetime must be shorter than, or equally as
```
long as, all three of the original reference lifetimes involved. In other words, we must convert to the shortest of the three lifetimes to `&'c`. Conversion from a reference `&'o` can be converted to to `&'p` if `'o` lives at least as long as `'p`, therefore:
* `The first argument &'c s1` already has lifetime `&'c`, so we don't have to do anything here.
But we now have the additional reference to check. We must now prove that the
* `&'b` outlives `&'c`, so we can convert `s2r: &'b` to `s2r: &'c`.
returned reference can have the same lifetime as the arguments of lifetime
* The returned reference has lifetime `&'c` already.
'&'s2'. This brings us to a second rule:
After conversion, the call-site satisfies the signature of `shorter()`, we have
> The return value of a function `&'r T` can be converted to an argument `&'s T`
proven the lifetimes in this program to be consistent, and therefore the
> if the lifetime of `&'r T` is equal or shorter than `&'s T`.
compiler accepts the program.
Now consider a slight variation on `main()` like this:
To make our program compile, we would have to subsitute `res: &'res` for `res:
&'s2`, but we can't since `&'res` in fact out-lives `&'s2`. This program is in
fact inconsistent and the compiler rightfully rejects the program because we
try make a reference (`&'res`) which outlives one of the values it refer to
(`&'s2`).
[Formally, function return values are said to be *contravariant*, the opposite
of *covariant*.]
How can we fix this porgram? Well if you were to swap the `let s2 = ...` with
the `res = ...` line, you would have:
```rust,ignore
```rust,ignore
fn main() {
fn main() {
let s1 = String::from("short");
let s1 = String::from("short");
let res;
let s2 = String::from("a long long long string");
let s2 = String::from("a long long long string");
let res;
res = shortest(&s1, &s2);
res = shortest(&s1, &s2);
println!("{}", res);
println!("{}", res);
}
}
```
```
De-sugared it looks like this:
Which de-sugars to:
```rust,ignore
```rust,ignore
fn main() {
fn main() {
'a {
's1 {
let s1 = String::from("short");
let s1 = String::from("short");
'b {
's2 {
let res: &'b str;
let s2 = String::from("a long long long string");
'c {
'res {
let s2 = String::from("a long long long string");
let res: &'res str;
'd {
res: &'res str = shortest(&'s1 s1, &'s2 s2);
// Annonymous scope for the borrows of s1 and s2
println!("{}", res);
// Assigning to the outer scope causes s1 and s2 to have 'b
res: &'b = shortest(&'d s1, &'d s2);
println!("{}", res);
}
}
}
}
}
}
}
}
}
```
```
XXX: Something is wrong. The above program does not compile, so we should be
Then at the call-site of `shortest()`:
able to show that the lifetimes are inconsistent. To do so we would to be have
* `&'s1 s1` outlives `&'s2 s2`, so we can replace the first argument with `&'s2 s1`.
to show that we can't convert `&'b` to `&'d`, but since `&'b` outlives `&'d`,
* `&'res str` lives shorter than `'&s2`, so the return value lifetime can become `res: &'s2 str`
we can. Hrmm.
Leaving us with:
```rust,ignore
res: &'s2 str = shortest(&'s2 s1, &'s2 s2);
```
Which matches the signature of `shortest()` and thus this compiles.
Intuitively, the return reference can't point to a freed value as the values