jmart
November 23, 2020, 11:32pm
1
Why does a match
on an inline value not act identically to declaring that value as a variable, when the cope of the arms is concerned?
let d = a.b().c();
match d {}
vs
match a.b().c() {}
I would expect there to be no difference in scope for the arms
Full example
Consider something like the below code. This runs without panic just fine, as would be expected.
use std::cell::RefCell;
use std::rc::Rc;
struct Node {
regen_at: Option<u32>,
energy: u32,
max_energy: u32,
}
fn schedule(regen_at: u32, task: impl 'static + FnMut()) {
// Save the task...
}
fn schedule_refresh(rc: Rc<RefCell<Node>>) {
let regen_at = 300;
rc.borrow_mut().regen_at = Some(regen_at);
schedule(regen_at, move || {
let mut cn = rc.borrow_mut();
cn.energy = cn.max_energy;
});
}
fn check_refresh(rc: Rc<RefCell<Node>>) {
let regen_at = rc.borrow().regen_at;
match regen_at {
Some(_) => (),
None => schedule_refresh(rc.clone()),
};
}
fn main() {
let node = Rc::new(RefCell::new(Node { regen_at: None, energy: 50, max_energy: 100 }));
check_refresh(node.clone());
let n = node.borrow();
println!("{:?}, {}, {}", n.regen_at, n.energy, n.max_energy);
}
(Playground )
However, if we change that match
in check_refresh
to put the variable in-line, this panics when that RefCell
is borrow_mut
'd in schedule_refresh
.
EDIT: I guess assignment does this too.
rc.borrow_mut().energy = rc.borrow().max_energy;
panics, even though the right side should be able to fully resolve before the left side.
There has to be a reason for this, I'm just curious what it is.
The rules about temporary lifetimes, especially in conditional expressions, are a bit inconsistent, but can't be changed significantly without breaking existing code. See this thread for some details:
Hello,
By my reasoning, the two while let -loop headers in the program below should be equivalent, but the commented-out one causes a panic, as the borrowed value is not dropped by the time control enters the loop body. Or am I missing something here?
This can be worked around by introducing an explicit inner let block, as shown in the code.
Is there some reason to keep the value alive so long?
After some googling, this seems to be connected to Non-Lexical Lifetimes development. Would this b…
3 Likes
jmart
November 24, 2020, 12:20am
3
Thanks, that was an interesting rabbit hole to read down.
jjpe
November 24, 2020, 4:47am
4
Perhaps this is one of those things that could be fixed with the introduction of a new edition?
Yandros adresses this in a link in that thread (source , emphasis not mine):
What to make of all this
This is one of the "quirks" of Rust, which proves that if explicit RAII semantics are wanted (such as with lock guards), then anonymous temporaries should be avoided . You may submit an RFC to change this, to get a change of temporaries drop
placement, but know that:
this would require, at least, a new edition
Having program semantics change with an edition change would be very weird (why should a line in Cargo.toml
change the semantics of a program without a compilation error? c.f. CString::new().as_ptr())
Thus this behavior cannot be changed .
On the other hand, I can see the issue of this being a particularly obscure thing for Rust, which goes against its "explicit semantics" philosphy: I thus think that filing an RFC for a warning lint against temporaries with drop glue in match would be a great thing to do, and if it fails, the lint could be added to clippy
instead.
Actually, it would be great if, in a similar fashion to #[must_use]
types, we could have #[time_sensitive_drop]
or #[must_drop_explicitely]
types.
1 Like
jmart
November 25, 2020, 4:27am
6
The previous threads were helpful - stumbled across an even older PR on this! From 2013.
https://github.com/rust-lang/rust/issues/6393
This then tracks through not one, but two other issues! Crossing all the way up to an open one in the present. Quite a rabbit hole.
jjpe
November 25, 2020, 5:04am
7
Well, strictly speaking the 2018 edition broke some code too. So it's not like it's unprecedented.
That said, the breakage was pretty limited in scope (<< 10% IIRC), and I'm not sure how much code such a change would break exactly.
system
Closed
February 23, 2021, 5:04am
8
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.