Should these trait implementations really be in conflict?

Hi,

I'm curious for an explanation about why the below trait implementations are conflicting.

In particular, String doesn't implement IntoIterator, so the first From shouldn't apply. This can be seen by commenting out the From<String> impl -- then the program does not compile because the A::from line in main has no resolution.

Thanks!

use std::slice;

struct A<'a, I>
where I: Iterator<Item = &'a u8>
{ 
    i: I
}

impl<'a, I, II> From<II> for A<'a, I>
where I: Iterator<Item = &'a u8>,
     II: IntoIterator<IntoIter=I, Item=&'a u8>
{
    fn from(ii: II) -> Self {
        A { i: ii.into_iter() }
    }
}

impl<'a> From<String> for A<'a, slice::Iter<'a, u8>>
{
    fn from(s: String) -> Self {
        A { i: s.as_bytes().iter() }
    }
}

fn main() {
    let i = A::from(String::from("hi"));
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0119]: conflicting implementations of trait `std::convert::From<std::string::String>` for type `A<'_, std::slice::Iter<'_, u8>>`:
  --> src/main.rs:18:1
   |
9  | / impl<'a, I, II> From<II> for A<'a, I>
10 | | where I: Iterator<Item = &'a u8>,
11 | |      II: IntoIterator<IntoIter=I, Item=&'a u8>
12 | | {
...  |
15 | |     }
16 | | }
   | |_- first implementation here
17 | 
18 |   impl<'a> From<String> for A<'a, slice::Iter<'a, u8>>
   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `A<'_, std::slice::Iter<'_, u8>>`
   |
   = note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `std::string::String` in future versions

error: aborting due to previous error

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

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

But it can at any moment, from the Rust's point of view. And you probably don't want to suddenly get a breakage in your code due to std update,

3 Likes

Huh, thanks for the explanation. I guess the compiler tells me that reasonably explicitly, but, in my defense, I've never heard of a compiler giving that kind of an error (i.e. "this would work, but because of something we might implement eventually it might not so we're not going to allow it").

Well, standard library is not special here - it's just another crate you depend on. So it's not "we might implement eventually", it's "implementing local trait for local type should not be breaking change".

3 Likes

I see.

I think this means that there is no way for me to provide a A::from(s) for a String s if I also want to support A::from(i) where i is an arbitrary iterator. In fact, I can't do A::from for any other types except types defined locally if I keep the arbitrary iterator implementation.

Thanks again...

You may want FromIterator instead, if you can live with having a different way to convert iterators vs. other types.

1 Like

I've been going down the FromIterator rabbit hole, and suspect I made a wrong turn.

I'm trying take make A::from_iter(e), where e produces &u8.

I started with this:

impl<'a, I> FromIterator<&'a u8> for A<'a, I>
where
I: Iterator<Item = &'a u8>
{
    fn from_iter<II: IntoIterator<Item=&'a u8>>(i: II) -> Self {
        A { i: i.into_iter() }
    }
}

which gives:


error[E0308]: mismatched types
  --> src/main.rs:16:16
   |
16 |         A { i: i.into_iter() }
   |                ^^^^^^^^^^^^^ expected type parameter `I`, found associated type
   |
   = note: expected type parameter `I`
             found associated type `<II as std::iter::IntoIterator>::IntoIter`
   = note: you might be missing a type parameter or trait bound

Ok. It needs to be told to unify the IntoIter and the I. I flailed through various approaches to this with no success. If I move the II to the impl, I get that it is "not constrained by the impl trait, self type, or predicates" (even when it apparently is constrained in the where clauses).

Is there a better way of approaching this? This project is trying to live within an "everything is an Iterator" paradigm, which Rust sortof feels like it wants to support -- except I am pretty quickly running into issues like the above. Maybe I need to give up on that kind of approach all together?

Hmm, right, you can't directly store the iterator there because it's a generic argument of the method, not applicable to Self. At most you could store it as a trait object, Box<dyn Iterator>.

FromIterator is really meant for consuming the iterator for its items, like its primary use in collect, so maybe that was a bad suggestion for your case.

Do you need it to be a trait? You could make an inherent A::from_iter constructor instead.

I'll do that, but I'll probably stay away from the A::from_iter -- I don't want to accidentally give the impression that I've implemented FromIterator...

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.