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<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)?
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.
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.
That’s what I thought at some point, too.
Author: Michael Lamparski <firstname.lastname@example.org>
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()`"
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
- Provides an interface for defining/iterating a chain of
- Has downcasting that actually works (unlike
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.
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.