Best practice for generic errors from a library in a trait?

Say I'm writing some library X that has some trait A. Trait A has a method, m(), that -> Result<(), some_error_type>.

My question is... What should some_error_type be, as a "best practice"? It shouldn't really be a library-specific error (e.g. XError), because the actual implementation is provided by the user. It shouldn't really be an anyhow error (or an eyre error, for that matter), because I don't want to force my user to using another crate at their level. Is &dyn std::error::Error the right choice here? Or, should I use thiserror, or anyhow, or something else? I'm open to using new crates if they solve the problem elegantly.

I should also mention that I expect the user to have numerous different error types within method m(), including custom errors and error types from other libraries. In a best-case scenario, they could use ? to propagate every form of error back, cleanly. Currently, I'm using a reference to the standard error trait, but I'm not certain that that's the best option.

Thanks in advance!

The trait can have an associated type for the error, allowing the implementor to provide whichever error type suits them.

trait A {
    type Error;
    fn m(&self) -> Result<(), Self::Error>;
}

If needed, you can constrain the type with traits, such as:

trait A {
    type Error: std::error::Error + Send + Sync;
    ...
4 Likes

Thanks, that's exactly what I was looking for, but I couldn't put my finger on it. Cheers!

As always, when in doubt, check what the standard library does.

2 Likes