2

I came across the section talking about lifetimes and was a little bit confused at first. So I decided to give it a go by coding a little example. (Playground)

fn main() {
    let b = "hello";
    let mut d = "Unassigned";
    {
        let a = "hi";
        let c = lifetime(&a, &b);
        d = &c;
    }

    // My confusion happens here, I was expecting a compile-time error
    // since the lifetime of 'c' is the same as 'a' which is in the previous block
    // from my understanding. But this compiles just fine
    println!("{}", d);
}

fn lifetime<'a, 'b>(test: &'a str, test2: &'b str) -> &'a str {
    println!("{}, {}", test, test2);
    return "returned value of lifetime";
}

From my understanding, the lifetime function binds the lifetime 'a to the returned reference value. So normally I would expect the line println!("{}", d); to break at compile time with an error referencing the lifetime 'a being out of scope, which I was wrong.

What did I understand wrong? Why is this code compiling?


I've seen this and that which basically just confused me further, because they somewhat say what I was expecting as a result in the first place.

E_net4
  • 27,810
  • 13
  • 101
  • 139
  • 1
    It may be useful to draw the lifetimes of those values on the side of the code. From there you'll see that the value bound by `a` will still live by the time it reaches that `println!`. See [this question](https://stackoverflow.com/q/42637911/1233251) for a more convoluted example that plays around with lifetime co-variance and contra-variance. – E_net4 Mar 23 '20 at 23:40
  • My understanding is that lifetimes are used to extend the knowlege of the compiler regarding object lifetimes beyound the lexical scope. You do not asign a lifetime to an object. You are merely telling the compler that the returned string reference lives at least as long as `b`, which is true since string literals are static and live for the duration of the entire program. You are then asigning the result to `d` and `d` itself lives until the end of `main`. – Hristo Iliev Mar 23 '20 at 23:45
  • 2
    Note that when returning references to string literals the proper lifetime is `'static`. – Hristo Iliev Mar 23 '20 at 23:47
  • This makes more sense now, I wasn't aware of contra-co-variance which infer the lifetime according to the longer living lifetime. [this](https://stackoverflow.com/questions/42637911/how-can-this-instance-seemingly-outlive-its-own-parameter-lifetime) as @E_net4removesmeta-commentary said actually answered part of my question. I'll let it open in case someone has more precision to this particular case – Scriptodude Mar 23 '20 at 23:56
  • Interestingly, when I try to get rid of warnings by changing `let mut d = "Unassigned";` to `let d;`, I get a compiler error similar to what you were expecting. (I can't explain why.) – J-L Mar 23 '20 at 23:57
  • @J-L it is because `d` becomes a `&&str` due to the `d = &c` assignment, it may be part of the problem actually ! – Scriptodude Mar 24 '20 at 00:00
  • @Scriptodude: You're right, I think. I changed the line to `let mut d: &str;`, and that ran without warnings. (I'm still confused about the original issue, though; does `c` somehow outlive its scope?) – J-L Mar 24 '20 at 00:06
  • I just saw @HristoIliev 's comment about when returning references to string literals the proper lifetime is `'static`. Makes more sense now. – J-L Mar 24 '20 at 00:13

1 Answers1

2

After finding out about contravariance as pointed out in the comment above, I wrote this little snippet (similar to the question)

struct Potato(i32);

fn doesnt_work() {
    let b = Potato(1);
    let d;
    {
        let a = Potato(2);
        let c = lifetime2(&b, &a);
        d = c;
    }

    // Compile-time error ! Borrowed value does not live long enough.
    println!("{}", d.0);
}

fn lifetime2<'a, 'b>(test: &'a Potato, test2: &'b Potato) -> &'a Potato {
    return &Potato(test.0);
}

Which now gives the actual expected compile-time error.

It finds out in my original question the lifetime was being inferred as 'static which is the highest common lifetime of str references.