-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Destructure drop structs #2061
Destructure drop structs #2061
Conversation
2. only owned structs can be destructured. | ||
|
||
# Detailed design | ||
[design]: #detailed-design |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The level of detail here seems low. Which solution is this RFC proposing? What are the pros and cons of the various options?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have added more details and tried to explain the pros/cons. I have also suggested to use the first approach (using an unsafe
block).
# How We Teach This | ||
[how-we-teach-this]: #how-we-teach-this | ||
|
||
Probably with a small section in the Nomicon, that explains why destrcuturing might be dangerous and under what circumstances it is allowed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: destructuring
Why should we *not* do this? | ||
|
||
# Alternatives | ||
[alternatives]: #alternatives |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another alternative is yet another automatically derived unsafe marker trait. Let's call it IndependentDrop
for now (bikeshed welcome). Any type without an explicit Drop
(autogenerated is fine) impl will be IndependentDrop
iff all its fields are IndependentDrop
. Destructuring of Drop
types is only possible if the type is also IndependentDrop
. Types like Vec
will unsafe impl<T> IndependentDrop for Vec<T> {}
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After reading it three times, it doesn't actually sound that bad.
Are all fields required to implement IndependentDrop
?
struct MyData {
i: InteriorUnsafe,
buf: Vec<u8>
}
MyData
should be safe to destructure into InteriorUnsafe
and Vec<u8>
. The only thing that isn't save to destructure is InteriorUnsafe
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are all fields required to implement IndependentDrop?
If MyData
implements Drop
, then its fields need to implement IndependentDrop
or you need to unsafe impl IndependentDrop for MyData {}
and thus guaranteeing that your destructor doesn't do shenigans with its inner types during the invocation of Drop::drop
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now it makes perfect sense. Adding this alternative to the RFC.
This is going to require runtime tracking like drop flags, I think. What happens if you only move some fields out of the struct? |
Oh. I was assuming that would not be allowed. |
We already do this tracking for the fields of non- |
Is there a particular reason that you discarded Approach 2/1+2 here? It seems to me that if there is a custom In addition, it seems that an approach including #2 would open up some other possibilities for making more flexible safe APIs. For example, I'm thinking there is a way that drop-by-value semantics could be added compatibly to the language in that case. |
I've wanted this since forever, but I also think that approach 2 is the best option. If you want to destructure a type outside of its defining module, then the module author should have given you a method to consume the value and return the parts that you want (something they can only safely do using approach 2). |
I don't think it's a good idea to have different semantics depending on the place of implementation. @canndrew Any arguments against Approach 2? |
I have changed the preferred approach of the RFC to Approach 2. |
I think I prefer a trait based approach, though approach 2 would be better than nothing. Approach 3 isn't designed correctly, however. Try this:
|
Do we have a solid answer as to whether the let mut i = InteriorUnsafe::new();
take_mut::take(&mut i.m, |m| {
drop(m); // Oh no
panic!();
}); Therefore I don't feel like there needs to be any restrictions on destructuring |
# Summary | ||
[summary]: #summary | ||
|
||
Allow destructuring of structs that implement Drop. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice if the RFC actually said what is destructuring before proceeding to motivation.
Especially given that the problem is not only about destructuring (in patterns), but about moving out individual fields in general. It can be done through any field access.
struct NonCopy;
let ds = DropStruct { individual_field: NonCopy, other_individual_field: NonCopy };
let f = ds.individual_field; // Moving out without destructuring.
// f is initialized, DROPPED
// ds is uninitialized, NOT DROPPED
// ds.individual_field is uninitialized, NOT DROPPED
// ds.other_individual_field is still initialized, DROPPED
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@petrochenkov
I did not intend to allow moving out individual fields, as that makes it too easy to forget the others.
(Will clarify this in the rfc)
I'd rather say the unsafety is |
I run into this fairly frequently, and the workarounds are usually very ugly. |
There are several competing scenarios for here, including : If you want to expose destructuring, then a If you just want to take apart your own type to avoid it's drop method, then you want to destructure it like any other type ala approach 2 :
I'm suspicious the ergonomics initiative "reforms" have broken this second usage by making some |
@rfcbot fcp postpone I could imagine wanting to do something like this eventually, but my feeling is that this is not the time. =) We are currently in the midst of a "from scratch" rewrite of the borrow checker to be basd on MIR, and so I am reluctant to make changes that would extend that task. Moreover, this particular task seems to get a bit harder in the MIR environment, because the distinction between I think I'd be open to revisiting this question once the MIR-based borrow checker is more stable, presuming that the proposal were rewritten to be based on MIR. |
Team member @nikomatsakis has proposed to postpone this. The next step is review by the rest of the tagged teams: No concerns currently listed. Once these reviewers reach consensus, this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
The final comment period is now complete. |
Closing as postponed. Thanks @s3bk for the RFC! |
Now that MIR and NLL have shipped it is a good time to revisit this? |
Rendered