The pattern of having an object-safe trait Foo
and a (potentially unsafe) extension trait FooExt
implemented for all instances of Foo
seems to become standard now.
https://github.com/rust-lang/rfcs/pull/445
This is a problem for me in the case of Iterator<A>
, as I have a library that overrides the default method IteratorExt#last()
of the old iterator trait (the underlying library has an efficient implementation of last()
). This in now impossible, because for any A
, there will always be a conflicting trait implementation of IteratorExt
, the one that libcore
already provides for all Iterator<A>
.
iterator.rs:301:1: 306:2 error: conflicting implementations for trait `core::iter::IteratorExt` [E0119]
iterator.rs:301 impl<'a, K: Key> iter::IteratorExt<Vec<u8>> for ValueIterator<'a,K,Vec<u8>> {
iterator.rs:302 fn last(&mut self) -> Option<Vec<u8>> {
iterator.rs:303 self.seek_last();
iterator.rs:304 Some(self.value())
iterator.rs:305 }
iterator.rs:306 }
...
Now, as far as I see, I have two options:
last()
implementation. That would mean it conflicts if IteratorExt
is imported unless carefully used. This also has the danger accidentally using an inefficient version of last()
if the version from IteratorExt
is used. I'd loose convenient access to IteratorExt
.seek_last()
). Disadvantage: I ask the user to learn vocabulary and to always favor my method over that provided by IteratorExt
. Same problem: I'd like to avoid accidental usage of last()
.Is there any other, better, solution I am missing?
As of rustc 0.13.0-nightly (8bca470c5 2014-12-08 00:12:30 +0000)
defining last()
as an inherent method on your type should work.
#[deriving(Copy)]
struct Foo<T> {t: T}
impl<T> Iterator<T> for Foo<T> {
fn next(&mut self) -> Option<T> { None }
}
// this does not work
// error: conflicting implementations for trait `core::iter::IteratorExt` [E0119]
// impl<T> IteratorExt<T> for Foo<T> {
// fn last(mut self) -> Option<T> { None }
//}
// but this currently does
impl<T> Foo<T> {
fn last(mut self) -> Option<T> { Some(self.t) }
}
fn main() {
let mut t = Foo{ t: 3u };
println!("{}", t.next())
println!("{}", t.last()) // last has been "shadowed" by our impl
println!("{}", t.nth(3)) // other IteratorExt methods are still available
}
Since you're not supposed to use Extension traits as generic bounds (but just to provide additional methods), this should theoretically work for your scenario, as you can have your own type and its impl
in the same crate.
Users of your type will use the inherent last
method instead of the one on IteratorExt
but still be able to use the other methods on IteratorExt
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With