4 ms·
It's weird to see lifetime correlations expressed as &'a &'b and not with where 'a: 'b I suppose I don't understand enough of how the first is diffe
by WirelessGigabit 3y ago
It's weird to see lifetime correlations expressed as
&'a &'b
and not with
where 'a: 'b
I suppose I don't understand enough of how the first is different from the second one, and how it impacts this issue.
- dannymi 3y agoIt's just a reference to a reference. It has nothing to do with lifetime correlations. Also, it's a lot less weird if you don't stop in the middle of the type. The entire type is for example &'a &'b u8 or &'a &'b () So the outer reference has lifetime 'a and the inner reference has lifetime 'b.
- Georgelemental 3y ago> It has nothing to do with lifetime correlations Yes it does; there's an implied `'b: 'a` outlives relationship that's required for the type to be well-formed.
- kbknapp 3y agoIn fact, I believe that's exactly where this bug lies. You're effectively able to trigger a case in which passing `&'a &'b` without providing any correlation (`where 'a: 'b`) that one would normally be required to provide makes the compiler behave as if those correlations were passed, albeit inferred incorrectly.
- LegionMammal978 3y agoThe first one creates an implied bound, while the second is an explicit bound. The important thing about implied bounds is that they allow late binding of lifetimes to function pointers (or closures): that is, you can have a single function pointer type like "for<'a> fn(&'a str)" that can be called with any lifetime 'a. Here, the lifetime 'a is called "late-bound", since it can be different with each call. In contrast, if a lifetime is subject to an explicit where bound, it must be "early-bound": each function pointer can must choose one particular value for that lifetime, that must be upheld for every call. For a practical example, you might have tried to declare a closure with a &T parameter, only to get lifetime errors when you call it twice. This is because the lifetime in the closure type is early-bound and must be the same for every call. (Sometimes the compiler figures out that a late-bound lifetime is desired, but the rules are very subtle. This is also why it's difficult to write a function that accepts a generic async closure.) Late binding is necessary for certain kinds of variance, which is a big part of this issue. Function pointers are contravariant in their parameters, which means if you have a type like "fn(&'short str)", you can cast it to "fn(&'static str)", since a 'static reference will always be valid for 'short. They're also covariant in their return type, so that "fn() -> &'static str" can be cast into "fn() -> &'short str". But when performing these variance transformations with late-bound lifetimes, the compiler doesn't always take into account the implied bounds in the source type properly, which allows you to perform casts that aren't actually sound.
- WirelessGigabit 3y agoEdit (since I cannot edit my comment after 2 hours): for the code to properly verify the lifetimes one needs to write where 'b: 'a meaning 'b is at least as useful as 'a. So 'b can live the same time, or longer, but not less.