-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
It would be great if there was a way to disable Drop for a type. What this would mean is that a value that can't dropped has to be moved or have data moved out of it to destroy it.
One use case for this is avoiding leaking threads by having threads that require a handle to the thread to be kept around. Basically, I'd like to write some code like this:
#[no_drop]
struct Thread<T> {
rx: Receiver<T>,
}
impl<T> Thread<T> {
fn spawn<F: FnOnce() -> T>(cls: F) {
let (tx, rx) = channel::<T>();
spawn(move |:| {
tx.send(cls());
});
Thread {
rx: rx,
}
}
// Block until the thread exits.
fn join(self) -> T {
let rx = self.rx; // move out of self so that self.drop()
// is not called at the end of the method
rx.recv()
}
}
The problem with writing this is that, if Thread can be dropped it defeats the whole point of the type. But if I implement Drop manually it's not possible to write the join method because it moves self. In today's Rust the closest thing I can do is put rx.recv() in drop() which means that drop() blocks (ew!), and means it's not possible to return a value from the thread.
How I see #[no_drop] working is just that the following code becomes illegal:
fn foo() {
let x = Thread::spawn(...);
// x falls out of scope without being moved. Compile error!
}
This is just one example of an application of linear types but I'm sure there are others. For example, a type for serious errors that can't be ignored and which the programmer is forced to handle. Sort of like the lint we have now for Result values but which is enforced.