How does an object without an owner know when to drop? [duplicate] - rust

Coming from C++, I'm rather surprised that this code is valid in Rust:
let x = &mut String::new();
x.push_str("Hello!");
In C++, you can't take the address of a temporary, and a temporary won't outlive the expression it appears in.
How long does the temporary live in Rust? And since x is only a borrow, who is the owner of the string?

Why is it legal to borrow a temporary?
It's legal for the same reason it's illegal in C++ — because someone said that's how it should be.
How long does the temporary live in Rust? And since x is only a borrow, who is the owner of the string?
The reference says:
the temporary scope of an expression is the
smallest scope that contains the expression and is for one of the following:
The entire function body.
A statement.
The body of a if, while or loop expression.
The else block of an if expression.
The condition expression of an if or while expression, or a match
guard.
The expression for a match arm.
The second operand of a lazy boolean expression.
Essentially, you can treat your code as:
let mut a_variable_you_cant_see = String::new();
let x = &mut a_variable_you_cant_see;
x.push_str("Hello!");
See also:
Why can I return a reference to a local literal but not a variable?
What is the scope of unnamed values?
Are raw pointers to temporaries ok in Rust?

From the Rust Reference:
Temporary lifetimes
When using a value expression in most place expression contexts, a temporary unnamed memory location is created initialized to that value and the expression evaluates to that location instead
This applies, because String::new() is a value expression and being just below &mut it is in a place expression context. Now the reference operator only has to pass through this temporary memory location, so it becomes the value of the whole right side (including the &mut).
When a temporary value expression is being created that is assigned into a let declaration, however, the temporary is created with the lifetime of the enclosing block instead
Since it is assigned to the variable it gets a lifetime until the end of the enclosing block.
This also answers this question about the difference between
let a = &String::from("abcdefg"); // ok!
and
let a = String::from("abcdefg").as_str(); // compile error
In the second variant the temporary is passed into as_str(), so its lifetime ends at the end of the statement.

Rust's MIR provides some insight on the nature of temporaries; consider the following simplified case:
fn main() {
let foo = &String::new();
}
and the MIR it produces (standard comments replaced with mine):
fn main() -> () {
let mut _0: ();
scope 1 {
let _1: &std::string::String; // the reference is declared
}
scope 2 {
}
let mut _2: std::string::String; // the owner is declared
bb0: {
StorageLive(_1); // the reference becomes applicable
StorageLive(_2); // the owner becomes applicable
_2 = const std::string::String::new() -> bb1; // the owner gets a value; go to basic block 1
}
bb1: {
_1 = &_2; // the reference now points to the owner
_0 = ();
StorageDead(_1); // the reference is no longer applicable
drop(_2) -> bb2; // the owner's value is dropped; go to basic block 2
}
bb2: {
StorageDead(_2); // the owner is no longer applicable
return;
}
}
You can see that an "invisible" owner receives a value before a reference is assigned to it and that the reference is dropped before the owner, as expected.
What I'm not sure about is why there is a seemingly useless scope 2 and why the owner is not put inside any scope; I'm suspecting that MIR just isn't 100% ready yet.

Related

Why does assigning a reference to a variable make me not able to return it

In this code:
fn main() {
let a = {
&mut vec![1]
};
let b = {
let temp = &mut vec![1];
temp
};
println!("{a:?} {b:?}");
}
Why is a valid and b not valid ("temporary value dropped while borrowed [E0716]")?
It would make sense to me if they were both problematic, why isn't the vec in a getting dropped?
Is this simply that the compiler can understand the first example but the second one is to hard for it to understand?
In one sentence: a is a temporary while b is not.
temp is a variable; variables are always dropped at the end of the enclosing scope. The scope ends before we assign it to b.
In contrast, the vec![] in a is a temporary, as it is not assigned to a variable. Temporaries are generally dropped at the end of the statement, however because the statement is a let declaration, the temporary inside it is subject to temporary lifetime extension and its lifetime is extended to match the lifetime of a itself, that is, until the enclosing block of a.
Note that to be precise, temp is also assigned a temporary that is subject to temporary lifetime extension - but its extended lifetime matches the lifetime of temp, as it is part of its declaration.

Where does the value live after it's borrowed in the function?

Consider below code:
fn main(){
let mut s = "Hi".to_string();
s.push_str(&" foo".to_string());
println!("{}",s);
}
We send reference of foo (i.e, a String not str) in push_str. But, we are not storing foo in any variable and just sending the reference.
Where does the value foo live for the reference to be valid inside of push_str.
As I'm just borrowing foo, how can I refer to foo (as a reference) later in my code i.e, after println?
Rust temporaries exist until the end of the current expression, and they can even be extended if necessary. The Rust compiler effectively creates a temporary variable for that temporary that you never see. This
s.push_str(&" foo".to_string());
is semantically equivalent to
{
let tmp = " foo".to_string();
s.push_str(&tmp);
}

Who has the ownership of a temporary value when it is created and referred by a struct? [duplicate]

Coming from C++, I'm rather surprised that this code is valid in Rust:
let x = &mut String::new();
x.push_str("Hello!");
In C++, you can't take the address of a temporary, and a temporary won't outlive the expression it appears in.
How long does the temporary live in Rust? And since x is only a borrow, who is the owner of the string?
Why is it legal to borrow a temporary?
It's legal for the same reason it's illegal in C++ — because someone said that's how it should be.
How long does the temporary live in Rust? And since x is only a borrow, who is the owner of the string?
The reference says:
the temporary scope of an expression is the
smallest scope that contains the expression and is for one of the following:
The entire function body.
A statement.
The body of a if, while or loop expression.
The else block of an if expression.
The condition expression of an if or while expression, or a match
guard.
The expression for a match arm.
The second operand of a lazy boolean expression.
Essentially, you can treat your code as:
let mut a_variable_you_cant_see = String::new();
let x = &mut a_variable_you_cant_see;
x.push_str("Hello!");
See also:
Why can I return a reference to a local literal but not a variable?
What is the scope of unnamed values?
Are raw pointers to temporaries ok in Rust?
From the Rust Reference:
Temporary lifetimes
When using a value expression in most place expression contexts, a temporary unnamed memory location is created initialized to that value and the expression evaluates to that location instead
This applies, because String::new() is a value expression and being just below &mut it is in a place expression context. Now the reference operator only has to pass through this temporary memory location, so it becomes the value of the whole right side (including the &mut).
When a temporary value expression is being created that is assigned into a let declaration, however, the temporary is created with the lifetime of the enclosing block instead
Since it is assigned to the variable it gets a lifetime until the end of the enclosing block.
This also answers this question about the difference between
let a = &String::from("abcdefg"); // ok!
and
let a = String::from("abcdefg").as_str(); // compile error
In the second variant the temporary is passed into as_str(), so its lifetime ends at the end of the statement.
Rust's MIR provides some insight on the nature of temporaries; consider the following simplified case:
fn main() {
let foo = &String::new();
}
and the MIR it produces (standard comments replaced with mine):
fn main() -> () {
let mut _0: ();
scope 1 {
let _1: &std::string::String; // the reference is declared
}
scope 2 {
}
let mut _2: std::string::String; // the owner is declared
bb0: {
StorageLive(_1); // the reference becomes applicable
StorageLive(_2); // the owner becomes applicable
_2 = const std::string::String::new() -> bb1; // the owner gets a value; go to basic block 1
}
bb1: {
_1 = &_2; // the reference now points to the owner
_0 = ();
StorageDead(_1); // the reference is no longer applicable
drop(_2) -> bb2; // the owner's value is dropped; go to basic block 2
}
bb2: {
StorageDead(_2); // the owner is no longer applicable
return;
}
}
You can see that an "invisible" owner receives a value before a reference is assigned to it and that the reference is dropped before the owner, as expected.
What I'm not sure about is why there is a seemingly useless scope 2 and why the owner is not put inside any scope; I'm suspecting that MIR just isn't 100% ready yet.

Is the official Rust book wrong about the borrow checker? [duplicate]

Coming from C++, I'm rather surprised that this code is valid in Rust:
let x = &mut String::new();
x.push_str("Hello!");
In C++, you can't take the address of a temporary, and a temporary won't outlive the expression it appears in.
How long does the temporary live in Rust? And since x is only a borrow, who is the owner of the string?
Why is it legal to borrow a temporary?
It's legal for the same reason it's illegal in C++ — because someone said that's how it should be.
How long does the temporary live in Rust? And since x is only a borrow, who is the owner of the string?
The reference says:
the temporary scope of an expression is the
smallest scope that contains the expression and is for one of the following:
The entire function body.
A statement.
The body of a if, while or loop expression.
The else block of an if expression.
The condition expression of an if or while expression, or a match
guard.
The expression for a match arm.
The second operand of a lazy boolean expression.
Essentially, you can treat your code as:
let mut a_variable_you_cant_see = String::new();
let x = &mut a_variable_you_cant_see;
x.push_str("Hello!");
See also:
Why can I return a reference to a local literal but not a variable?
What is the scope of unnamed values?
Are raw pointers to temporaries ok in Rust?
From the Rust Reference:
Temporary lifetimes
When using a value expression in most place expression contexts, a temporary unnamed memory location is created initialized to that value and the expression evaluates to that location instead
This applies, because String::new() is a value expression and being just below &mut it is in a place expression context. Now the reference operator only has to pass through this temporary memory location, so it becomes the value of the whole right side (including the &mut).
When a temporary value expression is being created that is assigned into a let declaration, however, the temporary is created with the lifetime of the enclosing block instead
Since it is assigned to the variable it gets a lifetime until the end of the enclosing block.
This also answers this question about the difference between
let a = &String::from("abcdefg"); // ok!
and
let a = String::from("abcdefg").as_str(); // compile error
In the second variant the temporary is passed into as_str(), so its lifetime ends at the end of the statement.
Rust's MIR provides some insight on the nature of temporaries; consider the following simplified case:
fn main() {
let foo = &String::new();
}
and the MIR it produces (standard comments replaced with mine):
fn main() -> () {
let mut _0: ();
scope 1 {
let _1: &std::string::String; // the reference is declared
}
scope 2 {
}
let mut _2: std::string::String; // the owner is declared
bb0: {
StorageLive(_1); // the reference becomes applicable
StorageLive(_2); // the owner becomes applicable
_2 = const std::string::String::new() -> bb1; // the owner gets a value; go to basic block 1
}
bb1: {
_1 = &_2; // the reference now points to the owner
_0 = ();
StorageDead(_1); // the reference is no longer applicable
drop(_2) -> bb2; // the owner's value is dropped; go to basic block 2
}
bb2: {
StorageDead(_2); // the owner is no longer applicable
return;
}
}
You can see that an "invisible" owner receives a value before a reference is assigned to it and that the reference is dropped before the owner, as expected.
What I'm not sure about is why there is a seemingly useless scope 2 and why the owner is not put inside any scope; I'm suspecting that MIR just isn't 100% ready yet.

Why does this iterator drop when not called directly as a function argument? [duplicate]

Coming from C++, I'm rather surprised that this code is valid in Rust:
let x = &mut String::new();
x.push_str("Hello!");
In C++, you can't take the address of a temporary, and a temporary won't outlive the expression it appears in.
How long does the temporary live in Rust? And since x is only a borrow, who is the owner of the string?
Why is it legal to borrow a temporary?
It's legal for the same reason it's illegal in C++ — because someone said that's how it should be.
How long does the temporary live in Rust? And since x is only a borrow, who is the owner of the string?
The reference says:
the temporary scope of an expression is the
smallest scope that contains the expression and is for one of the following:
The entire function body.
A statement.
The body of a if, while or loop expression.
The else block of an if expression.
The condition expression of an if or while expression, or a match
guard.
The expression for a match arm.
The second operand of a lazy boolean expression.
Essentially, you can treat your code as:
let mut a_variable_you_cant_see = String::new();
let x = &mut a_variable_you_cant_see;
x.push_str("Hello!");
See also:
Why can I return a reference to a local literal but not a variable?
What is the scope of unnamed values?
Are raw pointers to temporaries ok in Rust?
From the Rust Reference:
Temporary lifetimes
When using a value expression in most place expression contexts, a temporary unnamed memory location is created initialized to that value and the expression evaluates to that location instead
This applies, because String::new() is a value expression and being just below &mut it is in a place expression context. Now the reference operator only has to pass through this temporary memory location, so it becomes the value of the whole right side (including the &mut).
When a temporary value expression is being created that is assigned into a let declaration, however, the temporary is created with the lifetime of the enclosing block instead
Since it is assigned to the variable it gets a lifetime until the end of the enclosing block.
This also answers this question about the difference between
let a = &String::from("abcdefg"); // ok!
and
let a = String::from("abcdefg").as_str(); // compile error
In the second variant the temporary is passed into as_str(), so its lifetime ends at the end of the statement.
Rust's MIR provides some insight on the nature of temporaries; consider the following simplified case:
fn main() {
let foo = &String::new();
}
and the MIR it produces (standard comments replaced with mine):
fn main() -> () {
let mut _0: ();
scope 1 {
let _1: &std::string::String; // the reference is declared
}
scope 2 {
}
let mut _2: std::string::String; // the owner is declared
bb0: {
StorageLive(_1); // the reference becomes applicable
StorageLive(_2); // the owner becomes applicable
_2 = const std::string::String::new() -> bb1; // the owner gets a value; go to basic block 1
}
bb1: {
_1 = &_2; // the reference now points to the owner
_0 = ();
StorageDead(_1); // the reference is no longer applicable
drop(_2) -> bb2; // the owner's value is dropped; go to basic block 2
}
bb2: {
StorageDead(_2); // the owner is no longer applicable
return;
}
}
You can see that an "invisible" owner receives a value before a reference is assigned to it and that the reference is dropped before the owner, as expected.
What I'm not sure about is why there is a seemingly useless scope 2 and why the owner is not put inside any scope; I'm suspecting that MIR just isn't 100% ready yet.

Resources