How to handle error inside Drop trait impl

I need to implement the drop type for one of my types. However, I am calling a function that might return an error. Since the drop trait does not return an error, I am unsure what to do.

  1. I could just unwrap or panic with a custom message, but I read that that would cause a direct program termination if it's the second panic (i.e. we are currently already unwinding due to a prior panic).
  2. I could log the error, and thereby not panic at all.
    Are there any best practices to adhere to here?
    Here's the code snippet (though I think this is more of a general problem and not specific to this code):
impl Drop for TUI {
    fn drop(&mut self) {
        match self.exit() {
            Err(e) => panic!("Tearing down the TUI failed with: {}", e),
            _ => {}
        }
    }
}

Thanks!

Generally, don't design your destructor in a way that it needs to handle errors.

If you still do, then I don't think there's widespread consensus as to what you should do (whether to ignore the error or panic). I would personally prefer a panic because in most situations I encountered, a fallible destructor failing signified something serious or irrecoverable (e.g. not being able to rollback a transaction in a database), which I wouldn't want to be ignored.

A good alternative to an implicitly panicking destructor could be an explicit close() or destroy() method that takes ownership of self and returns it in an error if destruction fails.

7 Likes

It really depends on what you are doing in drop. If you're closing a file handle or terminating a tcp connections, you can ignore errors when the program is already panicking, as it doesn't matter at that point, as the OS will clean up anyway.

You can check if the thread is panicking with panicking in std::thread - Rust.

There isn't a common precedent in the standard library as far as I know. Sometimes we ignore errors in drop. Sometimes we panic on errors.

A third option is to do something similar to the drop_bomb crate to discourage implicit drop, and instead provide a fn destroy(self) -> Result<...> method. If we had linear types this might be a little less awkward.

3 Likes

Can you maybe explain a little more on the close() or destroy() methods? Do you mean I would explicitly have to call these methods myself before the lifetime of the Tui object ends? I like the convenience of not having to worry about calling a close() or destroy(), but I guess I am asking/expecting too much of Drop.

You would probably still have the Drop impl, but also provide a method that explicitly does the cleanup and can return a Result instead of ignoring or panicking on an error. The standard library kind of does this with File

Files are automatically closed when they go out of scope. Errors detected on closing are ignored by the implementation of Drop. Use the method sync_all if these errors must be manually handled.

6 Likes

Yes. There's no way to make Drop itself fallible.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.