# About the backwards compatibility of adding trait implementations

**URL:** <https://internals.rust-lang.org/t/about-the-backwards-compatibility-of-adding-trait-implementations/5650>\
**Category:** compiler\
**Created:** [July 29, 2017, 1:12am UTC](https://internals.rust-lang.org/t/about-the-backwards-compatibility-of-adding-trait-implementations/5650 "2017-07-29T01:12:28Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![jplatte](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jplatte/32/11437_2.png) [@jplatte](https://internals.rust-lang.org/u/jplatte)\
**Post date:** [July 29, 2017, 1:12am UTC](https://internals.rust-lang.org/t/about-the-backwards-compatibility-of-adding-trait-implementations/5650/1 "2017-07-29T01:12:28Z")

</div>

A few weeks back, I wanted to add a `char` to a `String`. After finding out that that is not currently possible, I tried to find out why and found an issue about it¹. It was closed with the comment

> Seems like something we shouldn't track, but would probably accept a PR for.

So I forked the rust repo, read the contributing guide and made sure building it without any modifications worked fine, then added two `impl`s: `impl Add<char> for String` and `impl AddAssign<char> for String`. After that though, as you can probably guess from the title, `rustc` did not build anymore. Some code in an external crate resulted in a compiler error when trying to add a `Cow<str>` to a `String`. After some debugging, I was able to figure out what had gone wrong: Previously, there only was a single `impl Add<_> for String` (the one for `&str`), and the compiler allowed deref coercion to happen from `Cow<str>` to `&str`. However, once there was a second `impl Add<_> for String`, the compiler didn't infer a deref coercion anymore, and the code trying to add a `Cow<str>` to a `String` failed to compile.

I have created a small repository² that showcases this bug, and while creating it, came up with another case where adding a trait implementation would result in a compiler error in code using the trait, this time without deref.

1: [impl AddAssign\<char\> for String · Issue #38784 · rust-lang/rust · GitHub](https://github.com/rust-lang/rust/issues/38784)  
2: [https://github.com/jplatte/rust-trait-impl-compatiblity](https://github.com/jplatte/rust-trait-impl-compatiblity)

---

<div class="post-metadata">

**Author:** ![Ixrec](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ixrec/32/6754_2.png) [@Ixrec](https://internals.rust-lang.org/u/Ixrec)\
**Post date:** [July 29, 2017, 1:28am UTC](https://internals.rust-lang.org/t/about-the-backwards-compatibility-of-adding-trait-implementations/5650/2 "2017-07-29T01:28:08Z")

</div>

This sounds like a typical case of “expected inference breakage” to me. What makes you think it’s a bug?

---

<div class="post-metadata">

**Author:** ![withoutboats](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/withoutboats/32/4560_2.png) [@withoutboats](https://internals.rust-lang.org/u/withoutboats)\
**Post date:** [July 29, 2017, 1:34am UTC](https://internals.rust-lang.org/t/about-the-backwards-compatibility-of-adding-trait-implementations/5650/3 "2017-07-29T01:34:48Z")

</div>

Ixrec is right that this is an inference failure, which we normally we have an allowance for, though inference failures in the operators are particularly troublesome becaus the conversion to the “explicit form” is pretty bad.

---

<div class="post-metadata">

**Author:** ![jplatte](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jplatte/32/11437_2.png) [@jplatte](https://internals.rust-lang.org/u/jplatte)\
**Post date:** [July 29, 2017, 12:23pm UTC](https://internals.rust-lang.org/t/about-the-backwards-compatibility-of-adding-trait-implementations/5650/4 "2017-07-29T12:23:08Z")

</div>

@Ixrec: I just thought adding trait implementations was supposed to preserve backwards compatibility. I can’t say that I know that this is written down somewhere, maybe this is a baseless assumption. But it seems very easy to accidentally break backwards compatibility if it is not the case. E.g. if the `String + Cow<str>` case wasn’t done in a dependency of the compiler or one of the tools that are built with it, and I had done a PR to add these impls, would somebody have caught this? I doubt it.

I understand that this is an inference breakage. I first thought that the compiler was being too clever by infering the type when there only was a single impl though. I suppose in the deref case the compiler could just do a better job at infering a deref coercion after the second impl is added.

Also, what about the generic literal case? Is this behaviour expected? If yes, again I’d argue that it makes accidental breaking changes very easy to do and hard to catch, if no then what is the desired behaviour? IMHO it doesn’t make sense to call either `Bar` impl when both exist in my example. Which would then mean that the compiler should always complain about calling the generic function with an `{integer}` whose type can’t be infered from anything else.

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [March 25, 2019, 8:28am UTC](https://internals.rust-lang.org/t/about-the-backwards-compatibility-of-adding-trait-implementations/5650/5 "2019-03-25T08:28:50Z")

</div>

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