4 ms·
Congrats! I've been excited about Rust for a while now, and this gives me a good reason to look into it a bit more. A quick question, though, if it's appropriat
by borrowwhatnow 11y ago
Congrats! I've been excited about Rust for a while now, and this gives me a good reason to look into it a bit more. A quick question, though, if it's appropriate in this context:
It seems to me that the borrow checker disallows behavior that I (perhaps naively) wouldn't be concerned about. For example, if I have this C snippet:
{ // Safe C
int *ptr = NULL;
int val = 42;
ptr = &val;
}
Everything is hunky-dory. Translating this to Rust results in this (I think):
{ // Malformed Rust
let ref: &i32;
let val = 42;
ref = &val;
}
Now the borrow checker tells me that "val" doesn't live long enough, because the reference comes to life before the value. It seems like this should be safe behavior, because the reference isn't bound to the value until after the value comes to life.
Can anyone shed some light on this for me? I'm all for safety, but this in particular seems like something that I should be allowed to do.
- koenigdavidmj 11y agoI'll assume you meant 'ref = &x' in your example. But what happens is that variables leave scope in reverse of the order in which they came in, so ref lives for slightly longer than val. This happens so that the order of destructors can be guaranteed.
- borrowwhatnow 11y ago> I'll assume you meant 'ref = &x' in your example. I did, thanks.
- Veedrac 11y agorefs don't have destructors. This happens because borrow scopes are always lexical. This is a bug, see https://github.com/rust-lang/rfcs/issues/811 https://github.com/rust-lang/rfcs/issues/811.
- nightpool 11y agoBug =/= language feature that we want that hasn't been implemented or designed yet, FWIW. Right now the borrow checker is currently performing to spec, but the spec is just a little too restrictive in some cases.
- Jweb_Guru 11y ago"Bug =/= language feature that we want that hasn't been implemented or designed yet, FWIW." In this case, I think the term is justified.
- IsTom 11y agoHonestly in my experience it's a deal-breaking bug. It's so awfully crippled compared to DDC regions.
- deleted 11y ago[deleted]
- lbarrett 11y agoI'm not an expert, but I think... Your ref can't be unassigned. There are no null pointers.
- steveklabnik 11y agoYou can define a binding without the value it's bound to: let x: i32; But you have to assign to it before you can use it.
- SamReidHughes 11y agoval ceases to exist before the reference ceases to exist, beacuse it's declared after. So after val is destroyed, the reference is invalid. Declare val earlier. Your code would be very nutty in C too.
- borrowwhatnow 11y agoI think I disagree with the "your code would be nutty in C" comment. Since C requires all variables to be declared at the top of the scope, and the order of declaration doesn't matter for purposes of allocation, there's no reason to worry about the ordering in this case.
- SamReidHughes 11y ago(C does not require all variables to be declared at the top of the scope.) Even if you're using a version of C that does, the order of variables implies something about their lifetimes and your code could make somebody refactoring more likely to believe they can lift the pointer out to the containing scope, or put the int in a smaller scope.
- amyjess 11y agoOnly C89 requires this. Compilers have moved on.
- mbrubeck 11y agoIn C the order of declaration and destruction doesn't matter as much, because C has no destructors. C++ would have similar issues, though.
- drbawb 11y agoMy understanding is this is due to the order in which slots are freed when they leave scope. Variables are dropped in the reverse order they are declared. So since `val` is declared after `ref` it leaves scope first, invalidating `ref`. So if you change the order of declarations like so[0]: { let x: i32; let y: &i32; x = 42; y = &x; } Then it is perfectly legal. [0]: http://is.gd/q8BQ18 http://is.gd/q8BQ18
- steveklabnik 11y agoWell, your first issue is that 'ref' is a keyword, so this doesn't work. Changing to just 'r', you get a 'not long enough' message. This is because you defined them in the order 'ref then val', but they would be destroyed as 'val' then 'ref'. That would leave 'ref' dangling, if even for a moment, like here. That'd be bad.
- borrowwhatnow 11y agoWell, that whole "ref" thing just shows my ignorance of Rust. Thanks for the information. > That would leave 'ref' dangling, if even for a moment, like here. That'd be bad. I'm not sure I agree that it would be bad (except maybe from a purity standpoint). Ref is unreachable during the time it is "pointing" to the out-of-scope "val", so nothing can actually reach the out-of-scope value through ref.
- steveklabnik 11y agoIn this specific instance, with these types, sure. Imagine you had two different types, with a destructor defined, which did things. Any amount of code can run between those two things being free'd.
- borrowwhatnow 11y agoTrue, but pointers don't have destructors in C++ or Rust, I think (and in C, there are no destructors at all, obvs).
- steveklabnik 11y agoThese particular references don't, but many smart pointers do. The borrow checker doesn't currently do something different based on Drop. You can argue that it would be easier if it just made this work, but at the same time, there would be more special cases. Right now, the rule is very simple. We'll see once SEME regions and or non-lexical borrows land, though...
- Jweb_Guru 11y ago