Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Irrefutable details in lifetime_bounds #656

Closed
critiqjo opened this issue Oct 31, 2015 · 5 comments
Closed

Irrefutable details in lifetime_bounds #656

critiqjo opened this issue Oct 31, 2015 · 5 comments

Comments

@critiqjo
Copy link

14.4.5 Bounds:

// In addition, the lifetime of `Ref` may not exceed `'a`.
struct Ref<'a, T: 'a>(&'a T);

A reference of T with lifetime 'a is guaranteed to satisfy the bound T: 'a. We cannot construct a T, which cannot be in Ref, but otherwise valid.
I think Ref should be a pair: struct RefPair<'a, 'b, T: 'b, U>(&'a T, &'b U);. Here the lifetime of T must not exceed 'b, and an example which doesn't satisfy that bound can be constructed, I think (haven't tried -- it might get coerced).

// In addition, `'a` must outlive the function.
fn print_ref<'a, T>(t: &'a T) where
    T: Debug + 'a {

'a will outlive the function, anyway. We cannot pass a reference to a function which does not live as long as the function itself, right? So why state it explicitly (with a "must")?

@mdinger
Copy link
Contributor

mdinger commented Oct 31, 2015

Your first point is good. I'm not particularly fond of adding more bounds but it is still a good idea to fix that.

For the second part, what you say may be true but the reader will not necessarily understand or believe it. Furthermore, it is meant to suggest that the reason you aren't allowed to construct a borrow which dies in the function is because of the explicit lifetime annotation. The fact that some of these lifetimes are or may be elide is discussed later.

@critiqjo
Copy link
Author

you aren't allowed to construct a borrow which dies in the function is because of the explicit lifetime annotation

I disagree. You cannot construct a borrow which dies in the function -- it's syntactically and semantically impossible.

The rule is: you "cannot move out of a borrow" -- which if had been allowed should basically "kill all (incl. other) references to the original object" which is impossible to check/analyze at compile-time (or even at runtime without significant performance penalties).

@mdinger
Copy link
Contributor

mdinger commented Oct 31, 2015

Then what do the lifetimes have to do with this at all then? Lifetimes are explained as the means by which the borrow checker keeps track of who outlives who; fn foo<'a, T>(x: &'a T) states 'a must outlive the function. If it is semantically impossible, why require the 'a everywhere? Why is elision even needed at all to make everything nicer?

@critiqjo
Copy link
Author

Every reference has an associated lifetime whether explicitly specified, or elided. fn foo<'a, T>(x: &'a T) is simply the complete representation of fn foo<T>(x: &T). For this particular line (or the function defined by it), 'a is of no use. Things get interesting only when two lifetimes interact.

For example, if &'a T is given to, say &'b mut U (which might be a struct with reference fields). Now the compiler must check if 'b outlives 'a, and if so, deny it.

@mdinger
Copy link
Contributor

mdinger commented Oct 31, 2015

Your reasoning seems sound. It was previously written from the standpoint that moving borrows don't work because of the lifetimes. Not because it was syntactically invalid.

Looking over the examples though, the difference seems fairly subtle for the most part and so reworking would probably also be subtle.

Regarding T: Debug + 'a {, I don't think it's a bad idea to reinforce that 'a must outlive the function.

If the lifetimes section was updated though, it might be a good idea to lift some of these ideas up to borrowing.

@critiqjo critiqjo closed this as completed Jan 1, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants