Adjust tail expression temporary scope chapter for new scoping rules#379
Adjust tail expression temporary scope chapter for new scoping rules#379dianne wants to merge 1 commit intorust-lang:masterfrom
Conversation
| ### Temporary scope may be narrowed | ||
|
|
||
| When a temporary is created in order to evaluate an expression, the temporary is dropped based on the [temporary scope rules]. Those rules define how long the temporary will be kept alive. Before 2024, temporaries from tail expressions of a block would be extended outside the block to the next temporary scope boundary. In many cases this would be the end of a statement or function body. In 2024, the temporaries of the tail expression may now be dropped immediately at the end of the block (before any local variables in the block). | ||
| When a temporary is created in order to evaluate an expression, the temporary is dropped based on the [temporary scope rules]. Those rules define how long the temporary will be kept alive. Before 2024, temporaries from tail expressions of a block would live past the block to the next temporary scope boundary. In many cases this would be the end of a statement or function body. In 2024, the temporaries of the tail expression may now be dropped immediately at the end of the block (before any local variables in the block). |
There was a problem hiding this comment.
I'd like to be deliberate about using "extended" only when it applies to temporary lifetime extension. I've reworded instances where it was used to refer to a temporary scope boundary not existing at all.
| // This example works in 2021, but fails to compile in 2024. | ||
| fn main() { | ||
| let x = { &String::from("1234") }.len(); | ||
| let x = { String::from(" 1234 ").trim() }.len(); |
There was a problem hiding this comment.
The old example compiles under rust-lang/rust#146098 so it needed some reworking to make the temporary not get extended. It's still contrived, but there's some realism to taking the length of a trimmed string.
| ``` | ||
|
|
||
| In this example, in 2021, the temporary `String` is extended outside of the block, past the call to `len()`, and is dropped at the end of the statement. In 2024, it is dropped immediately at the end of the block, causing a compile error about the temporary being dropped while borrowed. | ||
| In this example, in 2021, the temporary `String` lives past the call to `len()` and is dropped at the end of the statement. In 2024, it is dropped immediately at the end of the block, causing a compile error about the temporary being dropped while borrowed. |
There was a problem hiding this comment.
I couldn't think of a pleasant way to preserve all the details without wording it as if the absence of a temporary scope acts upon the temporary. Hopefully it still reads okay? I figure living past the .len() is the most important detail; since that happens in 2021, it implicitly lives past the block. Being dropped after the block tail is also still explicitly provided as the failure point in 2024 for contrast.
| The solution for these kinds of situations is to lift the block expression out to a local variable so that the temporary lives long enough: | ||
| One solution for these kinds of situations is to lift the temporary out to a local variable so that it lives long enough: | ||
|
|
||
| ```rust,edition2024 | ||
| fn main() { | ||
| let s = { &String::from("1234") }; | ||
| let x = s.len(); | ||
| let s = String::from(" 1234 "); | ||
| let x = { s.trim() }.len(); |
There was a problem hiding this comment.
Lifting the block expression out won't make a difference to drop order within the evaluation of an expression anymore, so we needed a new suggested fix. I've gone with a pretty general one and adjusted the wording to be less prescriptive to balance it out. I wouldn't want it to sound like that's the only fix when it makes the String live for the rest of the function; sometimes that's not ideal. Suggesting something like
let x = {
let s = String::from(" 1234 ");
{ s.trim() }.len()
};might be better morally for that reason, but it's less pretty in the common case.
This adjusts the wording and examples to accommodate rust-lang/rust#146098.