Problems when implements trait for trait

String : !Copy, but if I impl<F: Copy> X for F, then I can't impl X for String, because

upstream crates may add a new impl of trait std::marker::Copy for type std::string::String in future versions

That is ridiculous, if that will happen in the future, refuses the code at that time, why refuses it now.

How can I get through this

trait X {
    fn callx(&self);
}

impl<F: Copy> X for F {
    fn callx(&self) {
        println!("Copy");
    }
}

impl X for String {
    fn callx(&self) {
        println!("String");
    }
}

fn main() {} 

you have to make a choice between:

  1. it is a breaking change to add any trait impl to an existing type (even the type definition remains the same)

  2. disallow negative reasoning in checks for conflicting impls

It's balancing what is or isn't a breaking change. "Just error if it happens" makes adding an implementation a breaking (SemVer incompatible) change, which is too confining (libraries would stagnate or fragment with many major versions).

For this particular case, String won't ever implement Copy. But there is currently no way for it to opt into that guarantee so that your two implementations are accepted. There may be a way eventually.

In the meanwhile, you need to newtype String or avoid the blanket implementation.

1 Like