Is there (or will there be) an "official" or recommended error crate?


#1

When I started with Rust I found the error handling very painful. Then I discovered the ? operator and that seemed to make things work: until I hit the wall that it didn’t work at all if I called two functions that returned different types of error.

Fortunately, I then found the error-chain crate. This allows me to have return types of Result<()> or Result<SomeType> and to use the ? operator on different functions that return different error types (providing I specify these types using foreign_links; something I’ve found quite tricky to get right). Also I haven’t always found error-chain easy to use and have had to ask on this forum for help with it more than once.

However, there are other error handling crates, e.g., failure and quick-error. Is one of these (or some other) error handling crate the recommended one (or likely to be)?


#2

One will likely prevail, but there isn’t a best one yet. All that I know of have shortcomings, and the great thing is that we can work on all of them until we have a single good design.

The community did center around error_chain for a long while, but it has the disadvantage of being heavily macro-based. This makes it a bit hard to tell exactly what it’s creating.

Right now the up-and-coming crate is failure. It does a lot less than error_chain did, but that might be a good thing. It’s what I would recommend right now.


#3

Failure is an interesting alternate take on error handling. It provides, for example, type-erased errors, which you can use when you don’t want to handle errors but only log/display them before crashing the application.

I would say that so far, error-chain convinced me more for library usage (where you want to explicitly enumerate which errors can be emitted most of the time) and failure convinced me more for application usage (where you only want to terminate gently when an un-recoverable error occurs). As IIRC failure can ingest and wrap error-chain’s errors, the two can interoperate nicely.


#4

That’s what I thought at some point, too.

commit 4c1fc57b3c4e59e3410cd619593087605eda3996
Author: Michael Lamparski <diagonaldevice@gmail.com>
Date:   Mon Apr 30 00:30:26 2018 -0400

    migrate THE ENTIRE PROJECT to failure
    
    I wanted to gradually introduce 'failure' into the crate.
    To this end, I made the mistake of starting with rsp2-tasks
    [ed: the main application crate], because I figured, "error-chain
    errors can easily be converted into Error, while going the other
    way requires `.compat()`"
    
    well, uh
    
    turns out error-chain errors aren't Sync.

If you need to partially convert to failure, you gotta use it in libraries first.

failure isn’t that bad for libraries, but it’s a lot more work than error-chain. It’s best when you write your own Error types (preferably more than one for the whole crate; think of the standard library). It:

  • Eliminates boring Display and Error impls
  • Provides an efficient Backtrace tyoe
  • Provides an interface for defining/iterating a chain of causes
  • Has downcasting that actually works (unlike std::error::Error)

But:

  • You need to explicitly add the backtrace and cause fields. It’s your struct, after all.
  • It does not provide easy methods of construction. I have stuff like
    fn from_vec(vec: Vec<usize>) -> Result<PermVec, InvalidPermutationError> {
        if !Self::validate_data(&vec) {
            return Err(InvalidPermutationError(::failure::Backtrace::new()));
        }
        Ok(PermVec(vec))
    }
    
    and have manually implemented constructors on some of my larger error types.
  • It has no way to automate From impls. (In practice I have not written many myself, and have copped out by returning Result<T, Error> in places, knowing that the only client of these “libraries” is my application)

In summary, using failure in libraries does not feel much different from using nothing at all (i.e. std::error::Error). But it is a cost-effective (in terms of programmer effort) way of putting additional power at the consumer’s fingertips.


#5

Is one of these (or some other) error handling crate the recommended one (or likely to be)?

Note that if the community converges on a recommended error crate it will not be because someone decided it was the “official” one. Rather the opposite – a crate could be made “official” possibly by being included in the standard library, but only after the community has converged around it.