0

Please consider this example (playground):

struct Container<'short, 'long: 'short, T: 'long> {
    short_prop: &'short u8,
    long_prop: &'long T,
}

fn main() {
    let value = 9;
    let long = &value;

    {
        let short = &value;
        let res = Container {
            short_prop: long,
            long_prop: short, // why is this not an error?
        };

        println!("{} {}", res.short_prop, res.long_prop);
    }
}

In Container I specify 'long: 'short which I'm assuming means that 'long should live at least as long as 'short. In main, the variable long should live longer than short because it has a bigger scope.

So Container expects whatever goes into long_prop to live at least as long as whatever goes into short_prop. Yet the compiler is perfectly happy with me passing the longer-lived long into short_prop and the shorter-lived short into long_prop.

Is this because at the instantiation of Container the compiler narrows the lifetime of long to be equal to the lifetime of short thus satisfying the 'long: 'short constraint (since equality of lifetimes is fine)? Or is there another reason?

pretzelhammer
  • 13,874
  • 15
  • 47
  • 98
Attila Kun
  • 2,215
  • 2
  • 23
  • 33
  • I not seen a case in recent history where `'foo: 'bar` has been useful. Either it was redundant or **wrong** (when unsafe code was involved). – Shepmaster Feb 02 '21 at 21:01
  • 1
    See also [When is it useful to define multiple lifetimes in a struct?](https://stackoverflow.com/q/29861388/155423); [Why would you ever use the same lifetimes for references in a struct?](https://stackoverflow.com/q/44709632/155423) – Shepmaster Feb 02 '21 at 21:01
  • @Shepmaster I only saw `'foo: 'bar` here: https://chrismorgan.info/blog/rust-ownership-the-hard-way/ (ctrl-f for "DecodeResult") But I don't really understand that example. If anything, I'd expect the lifetime relationship to be `'decoded: 'buf` instead of `'buf: 'decoded` because the pointed (`'buf`) must live longer than the pointer (`'decoded`). But then again, that's only if we need this magic at all. – Attila Kun Feb 02 '21 at 22:41

1 Answers1

3

Is this because at the instantiation of Container the compiler narrows the lifetime of 'long to be equal to the lifetime of 'short thus satisfying the 'long: 'short constraint (since equality of lifetimes is fine)?

Yes.

Or is there another reason?

Nope.

Here's an example with a simpler Container struct which only holds 1 reference at a time. The reason it can hold both long and short references is because longer lifetimes are subtypes of shorter ones, but the overall lifetime of the container variable is narrowed to the minimum overlap of both of these lifetimes, which means container goes out of scope the same time as short does:

#[derive(Debug)]
struct Container<'a> {
    some_ref: &'a str
}

fn main() {
    let long = String::from("long");
    let long_ref = &long;
    
    let mut container = Container {
        some_ref: long_ref,
    };
    
    dbg!(&container);

    {
        let short = String::from("short");
        let short_ref = &short;

        container.some_ref = short_ref;

        dbg!(&container);
    } // both short & container go out of scope here
    
    dbg!(&container); // error, container dropped in block above, has same lifetime as short
}

playground

pretzelhammer
  • 13,874
  • 15
  • 47
  • 98