Problem with Display, From<ToString> traits

Hi,
I hit an interesting problem with this code (simplified):

use std::fmt;

struct Dummy(String);

impl<T:ToString> From<T> for Dummy {
    fn from(t:T) -> Self {
        Dummy(t.to_string())
    }
}

impl fmt::Display for Dummy {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Dummy: {}", self.0)
    }
}

fn main() {
    let d:Dummy  = "Dummy".into();
    println!("Hello, {}", d);
}

Code does not compile due to this error:

 Compiling playground v0.0.1 (/playground)
error[E0119]: conflicting implementations of trait `std::convert::From<Dummy>` for type `Dummy`:
 --> src/main.rs:5:1
  |
5 | impl<T:ToString> From<T> for Dummy {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: conflicting implementation in crate `core`:
          - impl<T> std::convert::From<T> for T;

Here is code on playground: Rust Playground

I think I roughly know what is going on:

  • ToString is automatically implemented for types implementing Display
  • thus in my implementation of impl<T:ToString> From<T> for Dummy T also matches Dummy
  • but there is also impl<T> From<T> for T in std, which also matches Dummy

and thus the conflict.

I guess in future specialization can resolve it. In the meanwhile is there any way how to implement these traits for Dummy - e.g. it can be both From<ToString> and Display ?

1 Like

How about impl<T: ToString + !fmt::Display>, does that work?

I guess, you don't want to rule out types that implement Display. In that case create DummyTrait that is only implemented for Dummy and then do impl<T: ToString + !DummyTrait>.

2 Likes

Also I quickly tried nightly with #![feature(specialization)], but it also does not work. So I'd also be interesting why specialization is not working in this case - impl<T:ToString> From<T> for Dummy should be more special that impl<T> From<T> for T?

  |
7 | impl<T:ToString+!DummyTrait> From<T> for Dummy {
  |                ^^^^^^^^^^^^ negative bounds are not supported

So this does not work - see some discussion here Need negative trait bound · Issue #42721 · rust-lang/rust · GitHub

That's a shame. Would've been too easy, of course.

So no solution? Any ideas anybody?

No, you can't have From<T: ToString> and Display implementing for the same type. Find another solution, e.g. don't use the From trait:

impl Dummy {
    pub fn new<T: ToString>(t: T) -> Dummy {
        Dummy(t.to_string())
    }
}

Thanks, understood, it's how std traits are set up.
But still wonder why specialization does not work? I thought that impl<T:ToString> From<T> for Dummy should be more 'special' sot it should fix the conflict?

To use specialization you have to mark one of them default, but since the one in std is the more general one, that is the one that needs the default marker, so you can't add it.

Oh, I see, but why I can have default for more specific type (implementing for my local type Dummy), if this type is local to crate it cannot do any harm elsewhere, or could it?

Since the one in the standard library is not marked default, other crates would be able to assume that, even in generic code, that if they call this implementation, they get the one in the standard library. If you could override it, that crate would not be able to assume this.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.