failure
failure copied to clipboard
Towards 0.2 and Beyond
With most of RFC 2504 being implemented in stable, I wanted to share my idea of how Failure should evolve towards. For preserving context, I'll briefly re-iterate what RFC 2504 entails:
Error::causeis being replaced byError::sourcein Rust 1.33, which supports downcasting of inner errors.std::error::Errorrequires a Display and Debug, which provides a string-based representation of the error.stdprovides a Backtrace module, which provides a minimal API for just printing a backtrace for end-users. This is not implemented yet, but @mitsuhiko indicated on December 28th, 2018 that he's working on the Backtrace implementation forstd1.
As @withoutboats indicated in RFC 2504, the Fail trait in Failure would become an extension trait to std:error::Error along the lines of:
trait ErrorExt: Error + Send + Sync + 'static {
// various provided helper methods
}
The Failure crate would then provide a derive for the standard library's error akin to:
#[derive(Debug, Display, Error)]
#[display = "My display message."]
struct MyError {
#[error(source)]
underlying: std::io::Error,
backtrace: Backtrace,
}
This new derive will be introduced in Failure 0.2. The corresponding derive of Fail can be removed with the release of 0.2, or more conservatively, marked as deprecated and removed entirely in Failure 0.3. The release of Failure 0.2 will come with a corresponding minimum Rust version bump to at least 1.31.
Additionally, while the following are not strictly bound to the release of Failure 0.2, we can also provide:
- Additional convenience macros and methods for chaining errors.
- More documentation and examples around different error-handling strategies.
Additionally, with Rust's increasing use in the network services space, a pain point that's emerged is best practices around error reporting to instrumentation systems. While the type_name intrinsic would be a great solution for this problem , it's currently nightly-only and blocked on specialization. Failure could patch this gap by introducing an associated const ERROR_TYPE: &'static str to ErrorExt for error-reporting purposes. This const can subsequently be removed and deprecated once specialization is available.
Feedback on this proposal is welcome and encouraged.
[1]: See the rust-lang Discord, the general channel. Relevant conversation reproduced below:
i was actually (sadly not on the machine i'm on holidays with right now) working on trying to make a patch for rust core that provides a backtrace api that's the missing piece right now to have stdlib provide what failure needs
Just for the record, this is probably related: https://users.rust-lang.org/t/announcing-err-derive-yet-another-error-handling-library/23594
- torkleyy tried to extract the derive macro
- Inspired by him, I tried how far could one get with std only (and got to the similar conclusion that everything except backtraces would work nicely, but there's not any reasonable way to get to the backtrace of some cause-of-cause error).
To be honest it's not very hard to come up with something better than failure soon given the pending changes to the stdlib. Once backtraces work I hope we will find a good path for failure and std error to converge.
Well, I think this issue is good news!
The only thing that concerns me is
The release of Failure 0.2 will come with a corresponding minimum Rust version bump to at least 1.31.
Does this also apply to the derive macro? I'm wondering whether it still makes sense to work on err-derive or if I can drop it in case failure can replace it.
@torkleyy Apologies for the delay. Yes, I think this should also apply to the derive macro.
Once backtraces work I hope we will find a good path for failure and std error to converge.
Related to this:
- Do you think it makes sense to wait for backtraces to land in std first, or start working on failure 0.2 without them (and either not release, release as -pre*/-alpha*, or maybe decide to do 0.3 if need be with backtraces)?
- Is there some rough time estimate for that?
I kind of feel there's a demand (is that the right word?) for something like failure::Error + derive, but on top of std::error::Error already. I (or someone else) could certainly release that as another separate crate, but that smells like fragmentation, which would be great to avoid.
@vorner
I think it’ll be okay to release a 0.2 without support for backtraces in std. At the very latest, I’d like to release Failure 0.2 before 1.33, which is February 28th, if I recall correctly. This allows for a coherent story around error-handling either regard to Error::cause’s deprecation.
With regard to deriving Error, I agree about the minimization of fragmentation ecosystem-wide.
As a single data point, @sapessi ran into a lot of issues with the current Fail derive in the AWS Lambda Runtime and replacing it with an Error derive would make things easier for library authors implementing error extensions, never-mind end users.
(sorry for not editing this comment more clearly; I’m short on time this afternoon and want to get my thoughts out.)
What would this mean for failure's Error struct?
@spinda: I was thinking of renaming it to DefaultError with suggestions in the documentation to rename failure::DefaultError to failure::Error when Error is the application's catch-all. Feel free to take a look at #296!
@davidbarsky If error handling is expressed as a graph, I currently use Failure's Fail trait to define "leaf node" errors, and Failure's Error struct to define "parent node" errors. Failure's Error struct essentially fills a similar role as Box<std::error::Error + Sync + Send> would do using just stdlib.
I don't feel the name DefaultError maps well to this use. I think it's because it's perfectly possible to create a specialized error type in one place, only for it to be converted back into the default later on. Reverting back to a "default" feels kind of odd.
For example: I think something like BoxedError, GenericError, or AnyError might hit closer to the mark (though ideally less verbose / not using already meaningful terms). I think it'd be nice if we could find a name that worked well for all uses.
@yoshuawuyts I responded to your comment on: https://github.com/rust-lang-nursery/failure/pull/296#issuecomment-456110251!
I ran into some roadblocks with the backtrace for std but I will try to get this done now. However I think failure in the meantime evolved a bit and there is probably more we would need on the stdlib error. In particular the name method is super useful for what we do at Sentry and I would love to see that appear on the std error as well.
Hello
Is there any progress? Is there anything people could do to help it move forward, or is it blocked on something external?
@vorner I haven't had the time to work on this, I'm sorry—a lot of life happened. This is something that others can/should pick up, as I think the initial issue described a path forward for the implementation.
Additionally, with the stabilization of core::any::type_name in 1.38, I think that the Fail::name method could be removed as well.
Hmm. I have quite a long queue of things I want to write myself, but maybe I could get to it sooner than you. No promises yet, though.