【注意！】トレイトの実装は破壊的変更である

# 問題

突然ですが問題です。あなたはRustのライブラリ開発者で、以下のようなAPIを公開しているとします。

```rust
// 有限な実数のみを扱う型
#[derive(Debug, PartialEq)]
pub struct FiniteFloat(f64);
```

さてここで、ユーザから「`FiniteFloat`型と`f64`型を直接等号比較できるようにしてほしい」というリクエストがあったとします。

そこであなたは、この`FiniteFloat`型に`PartialEq`トレイトを実装することにしました。

```rust
impl PartialEq<f64> for FiniteFloat {
    fn eq(&self, rhs: &f64) -> bool {
        self.0.eq(rhs)
    }
}

impl PartialEq<FiniteFloat> for f64 {
    fn eq(&self, rhs: &FiniteFloat) -> bool {
        self.eq(&rhs.0)
    }
}
```

さて、この変更は破壊的でしょうか？

# 破壊的な作用を及ぼす例

タイトルで既にネタバレしているように、これは破壊的変更です。例えば次のようなコードを考えます。

```rust
use finite_float::FiniteFloat;

/// 文字列を","で分割する関数
fn split_into_vec<T>(source: &str) -> Vec<T>
where
    T: FromStr,
    T::Err: std::fmt::Debug,
{
    source
        .split(",")
        .map(|part| part.parse().unwrap())
        .collect::<Vec<T>>()
}

fn main() {
    let result = split_into_vec("1.0,2.0");
    let expected = vec![1.0, 2.0];
    assert_eq!(expected, result);
}
```

これは先程の変更以前には問題なくコンパイルできていたコードです。では、先程のパッチを当ててコンパイルしてみます。

```console
$ cargo check
    Checking finite_float_test v0.1.0 (...)
error[E0284]: type annotations needed for `Vec<T>`
  --> src/main.rs:32:18
   |
32 |     let result = split_into_vec("1.0,2.0");
   |         ------   ^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the function `split_into_vec`
   |         |
   |         consider giving `result` the explicit type `Vec<T>`, where the type parameter `T` is specified
   |
   = note: cannot satisfy `<_ as FromStr>::Err == _`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0284`.
error: could not compile `finite_float_test`

To learn more, run the command again with --verbose.
```

コンパイルエラーを吐いてしまいました。

## なぜコンパイルエラーが生じたのか

変更を加える前は、`f64`は同じ`f64`に対してのみ`PartialEq`を実装していました。そのため、`Vec<f64>`に対して等号比較できるのは`Vec<f64>`だけであるため、コンパイラが`result`の型を`Vec<f64>`を推論することが出来ました。

しかし先程の変更により、`f64`は`PartialEq<FiniteFloat>`を実装するようになったため、`f64`と等号比較可能な型は`f64`または`FiniteFloat`のどちらかということになります。つまりコンパイラは`result`の型が`Vec<f64>`であるのか`Vec<FiniteFloat>`であるのかを`assert_eq!`の式から推論できなくなり、結果としてコンパイルエラーを生じてしまいました。

# 破壊的影響を及ぼす他の例

先程の例を見ると、問題を起こしているのは`impl PartialEq<FiniteFloat> for f64`の部分であるから、`impl PartialEq<f64> for FiniteFloat`のように自身の型に対してトレイトを実装するのは問題ないのではないか？と思う人がいるかもしれません。しかし実際にはこれも破壊的な変更になります。

例えば`FiniteFloat`が`FromStr`トレイトを既に実装しているとします。

```rust
impl FromStr for FiniteFloat {
    type Err = <f64 as FromStr>::Err;

    fn from_str(source: &str) -> Result<Self, Self::Err> {
        ...
    }
}
```

この時、先程のパッチを当ててみると次のようなコードのコンパイルが通らなくなります。

```rust
fn main() {
    let result = split_into_vec("1.0,2.0");
    let expected = vec![FiniteFloat(1.0), FiniteFloat(2.0)];
    assert_eq!(expected, result);
}
```

コンパイルが通らなくなる理由は先程述べたとおりです。

# まとめ

公開型に対して公開トレイトを実装した場合、コンパイラがトレイト境界から型を推論できなくなる場合があります。したがって、トレイトの実装は一部の例外を除いて破壊的な変更となるので、バージョン管理には充分気をつけましょう。

* [実際にトレイトの実装による破壊的変更が問題になった例](https://github.com/serde-rs/json/issues/357)
* [破壊的変更を及ぼす変更の一覧](https://rust-lang.github.io/rfcs/1105-api-evolution.html)（すべて列挙されているわけではない）

# コード全文

## 例1

```rust
use std::str::FromStr;

#[derive(PartialEq)]
pub struct FiniteFloat(pub f64);

// 下の実装は破壊的変更！！！
// impl PartialEq<f64> for FiniteFloat {
//     fn eq(&self, rhs: &f64) -> bool {
//         self.0.eq(rhs)
//     }
// }
// 
// impl PartialEq<FiniteFloat> for f64 {
//     fn eq(&self, rhs: &FiniteFloat) -> bool {
//         self.eq(&rhs.0)
//     }
// }

/// 文字列を","で分割する関数
fn split_into_vec<T>(source: &str) -> Vec<T>
where
    T: FromStr,
    T::Err: std::fmt::Debug,
{
    source
        .split(",")
        .map(|part| part.parse().unwrap())
        .collect::<Vec<T>>()
}

fn main() {
    let result = split_into_vec("1.0,2.0");
    let expected = vec![1.0, 2.0];
    assert_eq!(expected, result);
}
```

## 例2

```rust
use std::str::FromStr;

#[derive(Debug, PartialEq)]
pub struct FiniteFloat(pub f64);

impl FromStr for FiniteFloat {
    type Err = <f64 as FromStr>::Err;

    fn from_str(source: &str) -> Result<Self, Self::Err> {
        f64::from_str(source).map(|f| FiniteFloat(f))
    }
}

// 下の実装は破壊的変更！！！
// impl PartialEq<f64> for FiniteFloat {
//     fn eq(&self, rhs: &f64) -> bool {
//         self.0.eq(rhs)
//     }
// }
// 
// impl PartialEq<FiniteFloat> for f64 {
//     fn eq(&self, rhs: &FiniteFloat) -> bool {
//         self.eq(&rhs.0)
//     }
// }

/// 文字列を","で分割する関数
fn split_into_vec<T>(source: &str) -> Vec<T>
where
    T: FromStr,
    T::Err: std::fmt::Debug,
{
    source
        .split(",")
        .map(|part| part.parse().unwrap())
        .collect::<Vec<T>>()
}

fn main() {
    let result = split_into_vec("1.0,2.0");
    let expected = vec![FiniteFloat(1.0), FiniteFloat(2.0)];
    assert_eq!(expected, result);
}
```