I often manipulate object that have some release logic.
To illustrate the flaw in the current situation, I’ll take the example of BufWriter
.
Of course, nobody would ever want to write in a BufWriter
without flushing the result in the end.
Quite naturally, BufWriter
calls flush on Drop
(See BufferedWriter#Drop).
There are two problems to use Drop
to enforce release logic.
a) What if release can return an error. In the case of the BufWriter
, the call to flush()
may return an io Error that will be ignored by the BufWriter’s drop, and give us a false sense of safety : Any code that relies on Drop
to flush its BufWriter
is basically faulty
b) The call to Drop
is implicit. Putting complex logic in it, especially if it has performance impact, panics, or side-effect is a bad idea. Unfortunately release logic may be complex.
A simple solution could be to somehow able to declare the Drop
implementation as “private”. The effect would be that the object cannot be dropped from the scope outside of one of its method.
private impl Drop for BufWriter {}
After this addition, the compiler will not let any BufWriter to “leave the scope”.
To get his code to compile, the user would need to call a release function.
The name is up to the library writer, and there could be more than one for complex cases.
The idea is that it would use move semantics for self. For instance, in the case of the BufWriter
,
fn close(self) -> io::Result<()> {
if self.inner.is_some() && !self.panicked {
self.flush_buf()
}
else {
Ok(())
}
}
would make sense.
What do you think?