1

I have a trait MyIter that can implement Iterator trait. But I have no idea how to write this in rust. Below is my draft. but it has a compilation error: "type parameter T must be used as the type parameter for some local type ...".

trait MyIter {
    type ValueType;
    fn has_value(&self) -> bool;
    fn advance(&self) -> Wrapper<Self::ValueType>;
}
impl<T: MyIter> Iterator for T { // ERROR: type parameter T must be used as the type parameter for some local type
    type Item = Rc<RefCell<T::ValueType>>;
    fn next(&mut self) -> Option<Item> {
        self.advance().to_option();
    }
}

Below still doesn't compile.

trait MyAnotherIter: Iterator {
    type ValueType;
    type Item = Rc<RefCell<T::ValueType>>; // ERROR: associated type defaults are unstable.

    fn has_value(&self) -> bool;
    fn advance(&mut self) -> Wrapper<Self::ValueType>;

    fn next(&mut self) -> Option<Self::Item> {
        self.advance().to_option();
    }
}
Zoey Hewll
  • 4,788
  • 2
  • 20
  • 33
azyx
  • 35
  • 3
  • 1
    What should happen if someone implements both `MyIter` and `Iterator` (or if you implement `MyIter` for, say, `Range`, which is already the `Iterator`)? – Cerberus Oct 21 '22 at 02:05
  • It should be of no problem for a struct to implement both `MyIter` and `Iterator`. To avoid duplicate implementations, I want to let trait `MyIter` implement `Iterator`. – azyx Oct 21 '22 at 02:31
  • basically, this is because *external trait is not allowed for `impl` -ing for external types*. `Iterator` is an external trait, so `T` can only be local types. – xc wang Oct 21 '22 at 03:21
  • 1
    @azyx But if a struct implements `MyIter` and `Iterator`, which `Iterator` impl will it use? Its own or the one of `MyIter`? To prevent this ambiguity, the Rust compiler does not allow you to implement `Iterator` for `T: MyIter`. I think you are out of luck here. This situation would require negative trait bounds (e.g. `T: MyIter + !Iterator`) which [aren't stabilized yet](https://github.com/rust-lang/rfcs/issues/1834) and most likely won't be for quite a while, if ever. Additional, what xc_wang says is of course also a problem. – Finomnis Oct 21 '22 at 06:36

1 Answers1

0

The comments have pointed at this but I'll try to give a concrete example. Someone could write something like this code (I've only included the associated types but you can imagine their methods being defined however you like)

struct MyStruct {...}
impl Iterator for MyStruct {
    type Item = String;
    ...
}
impl MyIter for MyStruct {
    type ValueType = String;
    ...
}
// And there's also this from the blanket impl 
// impl Iterator for MyStruct {
//     type Item = Rc<RefCell<T::String>>;
//     ...
// }

And the rust compiler would have to decide, which impl of Iterator to use. The one from impl<T:MyIter> Iterator for T that you wrote, or impl Iterator for MyStruct that they wrote.

There currently isn't a way for the compiler to decide between two valid implementations, so it just doesn't let you get into that situation, by preventing you from making any blanket impl that could clash with someone's specific impl.


Both parts to your question seem to be, "how can I make my own iterator trait, and allow it to be used as a rust-style iterator", which is a case of the more general "How do I implement a trait I don't own for a type I don't own?"
The way we do that is by wrapping the foreign type in a wrapper type you do own:

struct MyIterator<T>(T);
impl<T:IterWrapper> Iterator for MyIterator<T>
{
    type Item = Rc<RefCell<T::ValueType>>;
    fn next(&mut self) -> Option<Item> {
        self.0.advance().to_option();
    }
}

Footnote: Regarding the second part of your question, I can only help with the associated item syntax that you got the error on:

trait MyAnotherIter: Iterator<Item = Rc<RefCell<Self::ValueType>>> {
    type ValueType;
    fn has_value(&self) -> bool;
    fn advance(&mut self) -> Wrapper<Self::ValueType>;
}

But this is incompatible with the wrapper solution above, and doesn't help you implement Iterator in terms of MyAnotherIter, so it's not really a solution.

Zoey Hewll
  • 4,788
  • 2
  • 20
  • 33