-
Notifications
You must be signed in to change notification settings - Fork 13.1k
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
Explain motivation behind lifetimes #36755
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @Manishearth (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice expanded example!
|
||
```rust | ||
fn foo() { | ||
let r = &0; // Introduce reference: r |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just write let r;
here. Initializing it to &0
and then re-assigning it later triggers another error because you didn't declare r
mutable, which is irrelevant to the point about lifetimes.
fn bar<'a>(x: &'a i32) { | ||
fn foo(id: u32) { | ||
let data = "#1=foo;#2=bar"; | ||
let v : &str; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style is usually let v: &str;
explicit in the function declaration: | ||
|
||
```rust | ||
fn data_value<'a,'b>(data: &'a str, key: &'b str) -> &'a str { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor style nit: <'a, 'b>
with space
["Lifetime Elision"][lifetime-elision] below) them in common cases. | ||
Before we get to that, though, let’s break the explicit example down: | ||
["Lifetime Elision"][lifetime-elision] below) them in common cases. Before we | ||
get to that, though, let’s look at a simple example with explicit lifetime: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lifetimes
"less than a week" and already helping with the docs! Thank you! |
Travis says:
You'll need to put "```rust,no_run" at the top of your examples when you know they won't compile. Or possibly there is a way nowadays to annotate them with the expected error, cc @GuillaumeGomez ? |
Took care of those issues hopefully.
Unfortunately I can't test the last one locally as the local Rust installation is interfering with the |
@durka: There is. If you expect an error, you have to add "compile_fail" and the expected error code (this second part isn't mandatory but it's better to have it). So for example:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for this! This is good overall, but some small nits.
@@ -50,29 +50,87 @@ complicated. For example, imagine this set of operations: | |||
4. You decide to use the resource. | |||
|
|||
Uh oh! Your reference is pointing to an invalid resource. This is called a | |||
dangling pointer or ‘use after free’, when the resource is memory. | |||
dangling pointer or ‘use after free’, when the resource is memory. In a | |||
simple case this would look like: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Teaching advice: I would stay away from "simple". Say something like "In a small case like this" or just "in a case like this."
The reason is, it might be simple to you, but not to your reader. If they hear you say "this is simple" and then they look at it and go "I have no idea what's going on", they get the impression that the topic isn't for them, and bail.
This applies almost universally in teaching, but especially in the chapter on the most complex topic in Rust 😄
|
||
To fix this, we have to make sure that step four never happens after step | ||
three. The ownership system in Rust does this through a concept called | ||
lifetimes, which describe the scope that a reference is valid for. | ||
three. In the simple example above the Rust compiler is able to report the issue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here
let data = "#1=foo;#2=bar"; | ||
let v: &str; | ||
{ | ||
let key = format!("#{}", id); // -o key goes into scope |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we use +
rather than o
elsehwere in this chapter for this
["Lifetime Elision"][lifetime-elision] below) them in common cases. | ||
Before we get to that, though, let’s break the explicit example down: | ||
["Lifetime Elision"][lifetime-elision] below) them in common cases. Before we | ||
get to that, though, let’s look at a simple example with explicit lifetimes: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here with simple
@@ -359,3 +418,4 @@ fn args<'a, 'b, T: ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command; // e | |||
fn new(buf: &mut [u8]) -> BufWriter; // elided | |||
fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a>; // expanded | |||
``` | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✂️
Changed to use
|
There seems to be some inconsistencies concerning the Which one is the preferred style for the examples? Without explicit
|
In general, without explicit main is considered best. Sometimes, you have to have it though. But 99% of the time, you don't. |
☔ The latest upstream changes (presumably #37090) made this pull request unmergeable. Please resolve the merge conflicts. |
Didn't see guidelines for resolving the merge conflicts. I went with merging master to the PR. Is this okay, or would a rebase on top of the new master have been preferred? Also curious on whether I should keep maintaining the PR. I'm guessing most of the documentation resources are going into rust-lang/book currently. If I should keep maintaining it, is there any status information? (Mainly I'm curious on whether this PR is in some kind of a limbo due to open change requests. Is there a way to mark those as "done". Couldn't find any documentation in the GitHub review article.) |
A rebase on top of the new master is better, actually.
Yes please! That book is still months out from launching, this helps everyone in the meantime. And since my focus is on that, it's extra valuable to have people help out here.
There's two reasons:
So first, let's fix that: @bors: r? @steveklabnik Second, I let me review this again, and then you can do the rebase and/or take care of any other nits, and then we can merge this. So sorry again. |
Yes, this looks great. If you can do that rebase, I can get this merged. Sorry again. |
Start the lifetime section with an explanation of the issues that lack of explicit lifetimes cause and how lifetimes alleviate these.
No problem! Was partly my fault to begin with as I didn't request you to review the code like suggested in the contribution guidelines. Rebase done. |
Thanks! @bors: r+ rollup |
📌 Commit cb90723 has been approved by |
⌛ Testing commit cb90723 with merge 9cb498d... |
💔 Test failed - auto-linux-cross-opt |
Seems like the auto-linux-cross-opt build was broken last night (UTC anyway) so I'm assuming there's nothing for me to do to get that resolved.
|
That's the same bogus failure from #37119. On Thu, Oct 13, 2016 at 11:47 AM, Mikko Rantanen notifications@github.com
|
@bors retry |
@bors: retry |
Explain motivation behind lifetimes Start the lifetime section with an explanation of the issues that lack of explicit lifetimes cause and how the explicit lifetimes solve these. ---------------- I had really hard time figuring out why I would need to care about the explicit reference lifetimes when going through the book at first. With strong background in C++, I'm familiar with the dangling reference problem - but given the section seems to focus more on the lifetime syntax and various ways to define lifetimes on functions and structs, I was unable to understand how they are used to solve the reference problem. This PR is an attempt at getting the reader to understand what the explicit lifetimes are used for and why they are an awesome thing instead of a bit of syntax that just has to be written. It's been less than a week that I've been diving into Rust so I'm far from certain about the terminology and technical correctness. I tried mimicking the existing terminology from the lifetimes section, but still no promises on getting it right.
Start the lifetime section with an explanation of the issues that lack of explicit lifetimes cause and how the explicit lifetimes solve these.
I had really hard time figuring out why I would need to care about the explicit reference lifetimes when going through the book at first. With strong background in C++, I'm familiar with the dangling reference problem - but given the section seems to focus more on the lifetime syntax and various ways to define lifetimes on functions and structs, I was unable to understand how they are used to solve the reference problem.
This PR is an attempt at getting the reader to understand what the explicit lifetimes are used for and why they are an awesome thing instead of a bit of syntax that just has to be written.
It's been less than a week that I've been diving into Rust so I'm far from certain about the terminology and technical correctness. I tried mimicking the existing terminology from the lifetimes section, but still no promises on getting it right.