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?
```rust,ignore
res: &'res = shortest(&'s2 s1, &'s2 s2);
```
But we now have the additional reference to check. We must now prove that the
returned reference can have the same lifetime as the arguments of lifetime
'&'s2'. This brings us to a second rule:
At the call-site of `shortest()`, the compiler must try to *convert* the lifetimes of
> The return value of a function `&'r T` can be converted to an argument `&'s T`
the references marked `&'a` in the signature of `shortest()`
> if the lifetime of `&'r T` is equal or shorter than `&'s T`.
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.
To make our program compile, we would have to subsitute `res: &'res` for `res:
* `&'b` outlives `&'c`, so we can convert `s2r: &'b` to `s2r: &'c`.
&'s2`, but we can't since `&'res` in fact out-lives `&'s2`. This program is in
* The returned reference has lifetime `&'c` already.
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`).
After conversion, the call-site satisfies the signature of `shorter()`, we have
[Formally, function return values are said to be *contravariant*, the opposite
proven the lifetimes in this program to be consistent, and therefore the
of *covariant*.]
compiler accepts the program.
Now consider a slight variation on `main()` like this:
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;
'c {
let s2 = String::from("a long long long string");
let s2 = String::from("a long long long string");
'd {
'res {
// Annonymous scope for the borrows of s1 and s2
let res: &'res str;
// Assigning to the outer scope causes s1 and s2 to have 'b
res: &'res str = shortest(&'s1 s1, &'s2 s2);
res: &'b = shortest(&'d s1, &'d s2);
println!("{}", res);
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