Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

E0119 error with generic trait implementation

I have an enum:

enum Field {
    Str(String),
    Integer(i64),
}

I want to do:

impl From<String> for Field {
    fn from(s: String) -> Field {
        Field::Str(s)
    }
}

impl<I> From<I> for Field where I: Into<i64> + Copy {
    fn from(i: I) -> Field {
        Field::Integer(Into::<i64>::into(i))
    }
}

This code above has an error:

error[E0119]: conflicting implementations of trait
`std::convert::From<std::string::String>` for type `Field`:
--> <anon>:12:5
   |
6  |          impl From<String> for Field {
   |  ________- starting here...
7  | |       fn from(s: String) -> Field {
8  | |         Field::Str(s)
9  | |       }
10 | |     }
   | |_____- ...ending here: first implementation here
11 | 
12 |       impl<I> From<I> for Field where I: Into<i64> + Copy {
   |  _____^ starting here...
13 | |       fn from(i: I) -> Field {
14 | |         Field::Integer(Into::<i64>::into(i))
15 | |       }
16 | |     }
   | |_____^ ...ending here: conflicting implementation for `Field`

String is not an implementor of Into<i64>, so why does error E0119 happen?

like image 321
tanagumo Avatar asked Mar 14 '17 04:03

tanagumo


1 Answers

TL;DR: where clauses don't count.


The crux of the issue is that the conflict detection is solely pattern based at the moment: it does not account for where clauses.

The problem is 3-fold:

  1. Deciding whether where clauses allow overlap or not is quite complicated,
  2. Deciding which where clause is more specialized than another is quite complicated (upcoming specialization),
  3. Allowing negative reasoning means that adding a trait implementation in the library code is now a breaking change.

The first two are purely implementation details, however the latter is a real concern in terms of language design. Imagine that:

  • your code doesn't have the Copy bound,
  • the Rust team decides to make parsing easier and add impl Into<i64> for &str.

And suddenly, there's a conflict where there was none before! You cannot upgrade!

So there's a real design choice here. You have to pick between:

  • being able to write impl that do not conflict (yet),
  • being able to upgrade your dependencies painlessly.

You can't have both.


Note: try typing Rust explain <code> in your search engine of choice, and behold E0119. Although it's not that helpful here.

like image 134
Matthieu M. Avatar answered Nov 07 '22 22:11

Matthieu M.