Conflicting implementations

I'm fairly new to Rust, so please excuse if this has been answered elsewhere (I can't find it)
Also apologies for lack of formatting, I can never remember how to get this forum to format code, and can't find any help about it either.

I want to define a type to deal with various kinds of error, so I tried the following:


pub struct FooError
{
	s: String,
}

impl<T> From<T> for FooError where T: ErrorTrait
{
	fn from(e: T) -> FooError
	{
		FooError::new(&format!("{}", &e))
    }
}

impl From<String> for FooError
{
	fn from(s: String) -> FooError
	{
		FooError::new(None, &s)
    }
}

The compiler complains that the impl for String conflicts with the generic one, because in the future someone may implemnt ErrorTrait for String.
Theoretically possible, but IMHO extremely unlikely.
So, how to work round this?
Is there no way to tell the compiler that I'm happy to take the risk of my code being broken in the future?
Grateful for any suggestions.

1 Like

It's pinned but it gets unpinned whenever you take a look at it. An easy way to find it is to Search -> Only return topics/posts -> dropdown -> are pinned.


To your actual question:

There is a question which will determine how to fix this: do you intend on using the capabilities of std::error::Error?

  • If so, you can leverage the fact that stdlib does exactly what you're trying to do and bounce off of that: impl one and impl two.
    pub struct FooError<'a> {
        error: Box<dyn ErrorTrait + 'a>,
    }
    
    impl<'a, T: 'a> From<T> for FooError 
        where Box<dyn ErrorTrait + 'a>: From<T> {
        fn from(x: T) -> Self {
            Self { error: x.into() }
        }
    }
    
  • If not, then you can rely on the fact that any T: Error must also be Display, and just work off of that:
    // Your original FooError definition
    impl<T: Display> From<T> for FooError {
        fn from(x: T) -> Self {
            Self { error: format!("{}", x) }
        }
    }
    
    Note, however, that this will work for anything which is display.

One thing which might work is to combine the approaches:

// Your original FooError definition
impl<'a, T: 'a> From<T> for FooError 
    where Box<dyn ErrorTrait + 'a>: From<T> {
    fn from(x: T) -> Self {
        Self {
            error: format!("{:?}", x.into())
        }
    }
}

However if you're performing this from call very often, it might be slightly slower, due to the use of trait objects.


No, by design. In theory everyone follows semver, and it's not a semver-breaking change to implement a trait (usually, ignoring special things like !Send [when dealing with multithreaded code] and Drop [when dealing with unions]).

Thanks for all the helpful explanation and suggestions. I tried the simpler one:

impl<T: Display> From<T> for FooError {
    fn from(x: T) -> Self {
        Self { error: format!("{}", x) }
    }
}

but it was rejected with

152 | impl<T: Display> From<T> for FooError
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: conflicting implementation in crate `core`:
            - impl<T> std::convert::From<T> for T;

I see what it's saying, but cannot see the use of the core crate conversion of any T into a T. What does this achieve, and when would it need to be done?

I also tried the 'combined' approach, which worked once I replaced x.into() with just plain x.

It's primarily there for use in generic bounds:

fn f(s: impl Into<String>) {
    dbg!(s.into());
}

fn main() {
    f("hello");                // &str
    f(String::from("World"));  // String
}