-1

In Rust docs, we see this example:

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

And explanation looks like this:

The function signature now tells Rust that for some lifetime 'a, the function takes two parameters, both of which are string slices that live at least as long as lifetime 'a. The function signature also tells Rust that the string slice returned from the function will live at least as long as lifetime 'a. In practice, it means that the lifetime of the reference returned by the longest function is the same as the smaller of the lifetimes of the references passed in

Note the words after "in practice". It mentions that:

In practice, it means that the lifetime of the reference returned by the longest function is the same as the smaller of the lifetimes of the references passed in

I don't understand why in practice, it means that lifetime of the returned is the same as the smaller of those 2 parameter's lifetimes. Is this something I need to memorize or what ? We can clearly say that parameters and returned values all have 'a same specifier. Why does Rust think that this means returned value should have smaller lifetime of those 2 passed ?

halfer
  • 19,824
  • 17
  • 99
  • 186
Nika Kurashvili
  • 6,006
  • 8
  • 57
  • 123
  • 1
    This looks strikingly similar to [your question from yesterday](https://stackoverflow.com/questions/71379840/what-does-smaller-mean-for-multiple-references-that-share-a-lifetime-specifier) – canton7 Mar 08 '22 at 12:06
  • @canton7 *which is defined by the scope of `x` and `y`* - Perhaps it'd be more precise to say: By the scope of whatever `x` and `y` borrow from, somewhere up in the call stack. – user4815162342 Mar 08 '22 at 12:15
  • I am wondering, in my example, why couldn't rust come up with a way to integrate this in elision rules ? what would be the contr-argument for this in terms of an example ? – Nika Kurashvili Mar 08 '22 at 12:49
  • 1
    Does this answer your question? [What does "smaller" mean for multiple references that share a lifetime specifier?](https://stackoverflow.com/questions/71379840/what-does-smaller-mean-for-multiple-references-that-share-a-lifetime-specifier) – Jmb Mar 08 '22 at 13:00
  • @Jmb nope. that's why I asked it again – Nika Kurashvili Mar 08 '22 at 13:02

1 Answers1

2

Why does rust think that this means returned value should have SMALLER lifetime of those 2 passed ?

Because that's the only thing that makes sense. Imagine this situation:

let a = "foo";              // &'static str
let s = "bar".to_string();  // String
let b = s.as_str();         // &str (non-static, borrows from s)

let longest = longest(a, b);

The lifetime of a is 'static, i.e. a lasts as long as the program. The lifetime of b is shorter than that, as it's tied to the lifetime of the variable s. But longest only accepts one lifetime!

What Rust does is compute a lifetime that is an intersection of the 'static lifetime of a and the tied-to-s lifetime of b, and uses that as the lifetime of (this invocation of) longest(). If such a lifetime cannot be found, you get a borrow checking error. If it can be found, it's no longer than the shortest source lifetime.

In the above case, the intersection of 'static and the lifetime tied to s is the lifetime tied to s, so that's what's used for the lifetime 'a in longest().

user4815162342
  • 141,790
  • 18
  • 296
  • 355
  • So compiler, when it comes to where `longest` function gets called, compiler still analyzis this part and knows what arguments are passed and what their scopes are. Then goes to `longest` function, just reads the signatures and also looks at what arguments longesst function can possibly return. The only thing it doesn't do is analyze the body of `longest` – Nika Kurashvili Mar 08 '22 at 12:18
  • I am wondering, in my example, why couldn't rust come up with a way to integrate this in elision rules ? what would be the contr-argument for this in terms of an example ? – Nika Kurashvili Mar 08 '22 at 12:50
  • 1
    @NikaKurashvili Analyzing the _caller_ for the purpose of lifetime elision wouldn't work because it would require knowing all the callers (which can be in different crates, etc.). Analyzing the _body_ for elision purposes wouldn't work because it would make it too easy to modify the signature by changing a detail of the implementation. Elision is intended to allow "obvious" syntax-sugar shortening of the full lifetime specs, for cases where the lifetimes are obvoius. (E.g. if the function takes one reference and returns one, it makes sense to just assume they have the same lifetime.) – user4815162342 Mar 08 '22 at 13:09