YA "conflicting implemenations" problem - negative reasoning?


#1

In this snippet:

struct Token /* { ... } */;

pub trait Tokenize {
    fn tokens(&self) -> Vec<Token>;
}

impl<T: Tokenize> Tokenize for Vec<T> {
    fn tokens(&self) -> Vec<Token> { self.iter().tokens() }
}

impl<IT, T> Tokenize for IT
    where IT: Iterator<Item=T>, T: Tokenize
{
    fn tokens(&self) -> Vec<Token> { self.flat_map(|t| t.tokens()).collect() }
}

The compiler complains that the implementation for Vec<T> conflicts with the more general Iterator implementation. I’m guessing this is something affected by https://github.com/rust-lang/rfcs/pull/1023, because Vec<T> might implement Iterator in future (despite this being very unlikely in practice).

So, 3 things:

  1. Is my diagnosis right?
  2. Could the compiler error message be more explicit about the problem? Because on the face of it, it doesn’t make much sense without knowing about the negative reasoning rules. Perhaps the explanation for E0119 could be expanded to include this case.
  3. What future extensions would allow something like this to be implemented? Is this something HKT could solve? Would it be possible to add negative implementations to tell the compiler that Vec<T> will never implement Iterator?

Thanks, J


#2

I suspect this is because you’re not in std and is related to the fact that you can’t implement Iterator for Vec (because it would be an orphan). std itself can do this; see the IntoIterator trait, which is defined for Vec and all iterators. Incidentally this might solve part of your problem: use IntoIterator instead of Iterator and Vec will become usable.

(In general, an iterator can only be read once, and there’s very little you can do with a shared reference to a generic Iterator, so the role will probably have to take self by-value.)