Hy there,
I have always wondered about a particularly aspect of the drop semantics, In the example from the recent introducing MIR Blog post the (pseudocodish) semantics of drop is shown in contexts where the value might be moved beforehand.
fn send_if(data: Vec<Data>) {
let mut data_is_owned = true;
if some_condition(&data) {
send_to_other_thread(data);
data_is_owned = false;
}
post_send();
// Free `data`, but only if we still own it:
if data_is_owned {
mem::drop(data);
}
}
So why wasn’t a semantic used witch specifies that “if the controll flow branches and a value is moved/droped in on branch, the moment the branches (possibly) come together again it assured to be dropped”
This sounds complex but (for me) would be kind of intuitive. The example from above would then be:
fn send_if(data: Vec<Data>) {
if some_condition(&data) {
send_to_other_thread(data);
} else {
mem::drop(data)
}
post_send();
}
This would also overlap with the analysis the borrow checker already does.
Note that in case of a return in a branch the graph would “join” again on the return e.g.:
fn send_if(data: Vec<Data>) {
if some_condition(&data) {
send_to_other_thread(data);
return
}
post_send();
mem::drop(data)
return
}
Through I’m not sure if this would make a measurable difference in speed on a modern computer it might be preferable in more close to metal applications due to really having zero-overhead.
Also I can’t come up for a good reason against this pattern, but given that e.g. some unsafe+asyn code might depend on this semantics (and fail in a very subtile manner) changing to it probably a nogo and if you really want this behavior you could write all the “drop on join” statements per hand => all (in the future existing) flags will be optimized away (but it’s just to much to do per hand )
So why was the variation with slightly more overhead chosen or to rephrase witch point(s) did I miss?