Implementing an error struct

The code below illustrates Error behaviour which, I think, is reasonably desirable but I don't know how to achieve it. Does anyone know of any solutions?

#[derive(Debug)]
pub struct MyError {
    pub code: u16,
    pub reason: String,
}

impl<E> From<E> for MyError
where
    E: std::fmt::Display,
{
    fn from(value: E) -> Self {
        Self {
            code: 400,
            reason: value.to_string(),
        }
    }
}

impl std::error::Error for MyError {}
impl std::fmt::Display for MyError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "[{}] {}", self.code, self.reason)
    }
}
// error[E0119]: conflicting implementations of trait `std::convert::From<MyError>` for type `MyError`
//  --> src/main.rs:7:1
//   |
// 7 | impl<E> From<E> for MyError
//   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
//   |
//   = note: conflicting implementation in crate `core`:
//           - impl<T> std::convert::From<T> for T;

fn main() {
    let err: MyError = "testing".into();

    let any_err: Box<dyn std::error::Error> = Box::new(err);
    assert_eq!(any_err.to_string(), "[400] testing".to_string());
}

There's no way to write the blanket implementation in a non-overlapping way and still implement Error.

You could implement for some set of common types instead (From<String>, From<&str>).

1 Like

Can I, say, do something like this?

impl<E> From<E> for MyError
where
    E: std::fmt::Display + (&str | String | ...),
{
...
}

Rust doesn't have "or bounds" (nor type equality bounds outside of associated types), so not like that.

You could use a macro.

macro_rules! my_error_from {
    ($($t:ty),* $(,)?) => { $(
        impl From<$t> for MyError {
            fn from(value: $t) -> Self {
                Self {
                    code: 400,
                    reason: value.to_string(),
                }
            }
        }
    )*}
}

my_error_from!(String, &str, i32,);

Thanks; Hopefully future rust has a more general solution :crossed_fingers:

There's no real solution to this problem; the impls contradict coherence, so it can't be "fixed". The problem is inherent, it's not a missing feature.

Are you able to go in to more detail why the is no real solution? I haven't worked out for myself why From conflicts with the Display impl.

I've seen discussions on specialization and exclude patterns (`E: Xtrait + !Ytrait); do these upcoming language features not help?

T implements From<T> and Into<T>. But your blanket implementation also tries to implement From<MyError> for MyError, since MyError implements Display.

Specialization could help but there's currently no roadmap to stabilize specialization as far as I know.

I don't see how negative bounds could help, and they may not be what you think they are (it means a type has explicitly opted out of ever[1] implementing a trait, not that it merely hasn't implemented a trait).


  1. until the next major version â†Šī¸Ž

1 Like

MyError is Display, so your From impl applies to MyError itself (since it meets the Display bound). That conflicts with the standard library's transitive From<T> for T impl.

1 Like