2 ms·
This is also why, in Rust, relying on drop to close a file (which ironically is the poster child for RAII) is a bad pattern. Closing a file can raise errors but
by nextaccountic 2y ago
This is also why, in Rust, relying on drop to close a file (which ironically is the poster child for RAII) is a bad pattern. Closing a file can raise errors but you can't reasonably treat errors on drop.
What we really need is a way to handle effects in drop; one way to achieve that is to have the option to return Result in a drop, and if you do this then you need to handle errors at every point you drop such a variable, or the code won't compile. (This also solves the async drop issue: you would be forced to await the drop handling, or the code wouldn't compile)
- surajrmal 2y agoI actually really like this idea. Is there somewhere I can read more about it?
- masklinn 2y ago> This is also why, in Rust, relying on drop to close a file (which ironically is the poster child for RAII) is a bad pattern. Is it though? It ensures the fd is closed which is what you want, and if you have some form of unwinding in the language you can't really ask for more. And aborts are, if anything, worse. It also works perfectly well for reading, there's no value to close errors then. > Closing a file can raise errors but you can't reasonably treat errors on drop. It's mostly useless anyway, since close does not guarantee that the data has been durably saved. If you want to know that, you need to sync the file, and in that case errors on close are mostly a waste of time: - if you've opened the file for reading you don't care (errors are not actionable, since you can't retry closing on error) - if you've flushed a write, you don't care (for the same reason as above) The one case where it matters is if you care but missed it, in which case we'd need a bunch of different things: - a version of must_use for implicit drops - a consuming flush-and-close method on writeable files - a separate type for readable and writeable files in order to hook both, and a suite of functions to convert back and forth because even if rust had the subtyping for you don't want to move from write to read without either flushing or explicitly opting out of it as you're moving into a "implicit drop is normal" regime > one way to achieve that is to have the option to return Result in a drop, and if you do this then you need to handle errors at every point you drop such a variable That is nonsensical, the entire point of drop is that it's a hook into default / implicit behaviour. How do you "handle errors" when a drop is called during a panic? It also doesn't make sense from the simple consideration that you can get drops in completely drop-unaware code. Consuming methods is what you're looking for.
- bqmjjx0kac 2y agoYou can kind of achieve this at runtime like so struct Foo { bool dirty, } impl Foo { fn clean_up(&mut self) { // ... self.dirty = false; } } impl Drop for Foo { fn drop(&mut self) { if self.dirty { panic!("Foo was not cleaned up before its lifetime ended"); } } } fn bar(foo: &mut foo) { foo.clean_up(); }
- surajrmal 2y agoA method which takes foo and turns it into another type is slightly better. You can then unconditionally panic in the drop impl.
- bqmjjx0kac 2y agoNeat, I didn't realize that would skip drop()!
- nh2 2y ago> close a file (which ironically is the poster child for RAII) Yes, I call this "RAII is a lie" (T-shirt pending). Closing file descriptors is univerally used to showcase RAII, but it should never be used for that. C++ has the same problem: https://github.com/isocpp/CppCoreGuidelines/issues/2203 https://github.com/isocpp/CppCoreGuidelines/issues/2203 In there, it is acknowledged that a manual Close() should always be provided, and used if you want guarantees. > is a bad pattern Good that Rust at least figured it out early that it's a bad pattern! Never use RAII in situations where the cleanup can fail!