Say I have this code:
pub trait A {}
pub trait B {}
pub trait SomeBehavior {
fn func() -> bool;
}
And I want to provide the blanket implementation for A and B like this:
impl <T> SomeBehavior for T where T: A {
fn func() -> bool { true }
}
impl <T> SomeBehavior for T where T: B {
fn func() -> bool { false }
}
But this gives following error:
error[E0119]: conflicting implementations of trait `SomeBehavior`
--> src/lib.rs:12:1
|
8 | impl <T> SomeBehavior for T where T: A {
| -------------------------------------- first implementation here
...
12 | impl <T> SomeBehavior for T where T: B {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
Why the compiler treats two different implementations on different traits as same implementation?
Rust has the concept of "trait coherence" which is the idea that for any combination of type and trait there should be at most one implementation of that trait. This is the concept that guides Rust's "orphan rule" and is designed to ensure that conflicting implementations can't occur in downstream crates.
So the problem with the two blanket implementations above is the possibility that a type can implement both A and B. There would then be two possible implementations for SomeBehavior for that type.
struct MyType;
impl A for MyType;
impl B for MyType;
let t = MyType;
let _ = t.func(); // how to choose?
Its not particularly well documented part of Rust unfortunately; likely because its complicated, its contentious, the rules have changed over the years, and will likely change again in the future. Resources are scattered between blog posts, RFCs, and issues but you can find the important bits in the Coherence section of the chalk book (the next-generation trait-solver).
There may be features added in the future that may allow this or something similar:
negative impls (unstable feature)
specialization (RFC)
crate-level where-clauses (blog article by Niko Matsakis)
Related
Say I have this code:
pub trait A {}
pub trait B {}
pub trait SomeBehavior {
fn func() -> bool;
}
And I want to provide the blanket implementation for A and B like this:
impl <T> SomeBehavior for T where T: A {
fn func() -> bool { true }
}
impl <T> SomeBehavior for T where T: B {
fn func() -> bool { false }
}
But this gives following error:
error[E0119]: conflicting implementations of trait `SomeBehavior`
--> src/lib.rs:12:1
|
8 | impl <T> SomeBehavior for T where T: A {
| -------------------------------------- first implementation here
...
12 | impl <T> SomeBehavior for T where T: B {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
Why the compiler treats two different implementations on different traits as same implementation?
Rust has the concept of "trait coherence" which is the idea that for any combination of type and trait there should be at most one implementation of that trait. This is the concept that guides Rust's "orphan rule" and is designed to ensure that conflicting implementations can't occur in downstream crates.
So the problem with the two blanket implementations above is the possibility that a type can implement both A and B. There would then be two possible implementations for SomeBehavior for that type.
struct MyType;
impl A for MyType;
impl B for MyType;
let t = MyType;
let _ = t.func(); // how to choose?
Its not particularly well documented part of Rust unfortunately; likely because its complicated, its contentious, the rules have changed over the years, and will likely change again in the future. Resources are scattered between blog posts, RFCs, and issues but you can find the important bits in the Coherence section of the chalk book (the next-generation trait-solver).
There may be features added in the future that may allow this or something similar:
negative impls (unstable feature)
specialization (RFC)
crate-level where-clauses (blog article by Niko Matsakis)
I want to implement the frequent math multiplication of a vector by a scalar: k * v = (k * v0, k * v1, k* v2..). The code is the following:
#[derive(Debug)]
struct V(Vec<i32>);
impl std::ops::Mul<V> for i32 {
type Output = V;
fn mul(self, v: V) -> V {
V(v.0.iter().map(|v| v * self).collect())
}
}
fn main() {
let v = V(vec![1,2]);
println!("{:?}", 3 * v);
}
This solution works, however I would like to avoid the definition of the struct V, and instead code something like that:
impl std::ops::Mul<Vec<i32>> for i32 {
type Output = Vec<i32>;
fn mul(self, v: Vec<i32>) -> Vec<i32> {
v.iter().map(|v| v * self).collect()
}
}
Which throws the following error:
only traits defined in the current crate can be implemented for arbitrary types
--> src/main.rs:45:1
|
45 | impl std::ops::Mul<Vec<i32>> for i32 {
| ^^^^^-----------------------^^^^^---
| | | |
| | | `i32` is not defined in the current crate
| | `Vec` is not defined in the current crate
| impl doesn't use only types from inside the current crate
|
= note: define and implement a trait or new type instead
Is possible to use the multiplication trait for foreign types?
In short, no.
You're running into the "orphan rule". The basic idea is that if you want to implement a trait X, on a struct/enum/union Y, at least one of those must be defined in the current crate.
This is somewhat restrictive at times, but it is a product of Rusts "coherence rules". In general, every combination of traits and types must have at most 1 implementation. So the following code is not valid:
struct Wrapper<T>(T);
trait Print {
fn print(&self);
}
impl Print for Wrapper<i32> {
fn print(&self) {
println!("a very special int: {}", self);
}
}
impl<T: Display> Print for Wrapper<T> {
fn print(&self) {
print!("a normal type: {}", self);
}
}
Imagine you write in your code 0i32.print(). Which implementation does rustc choose? The answer is unclear (in a pre-specialization world), so given Rust's principle of being explicit, the code is outright rejected.
The orphan rule is a mechanism that generally makes the ecosystem more usable. There's nothing inherently unsound about breaking the orphan rule (if it were possible), however, it leads to an unfortunate scenario where you might use 2 crates that define their own implementations for certain foreign types and traits.
Imagine, for example, a crate decides to add this (fairly reasonable looking) implementation:
impl<T> Display for Vec<T> where T: Display {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
todo!()
}
}
This is fine, until you want to import another crate also defines a similar impl. Even if the code is identical, these would be separate implementations, and therefore would be incoherent and would fail to compile.
The orphan rule protects the ecosystem from this sort of problem.
Wrappers are idiomatic in Rust, and don't impose a runtime cost. If you find yourself writing a lot, I have written a library to automate a lot of the boilerplate called microtype which may be useful.
I want trait implementations in Rust to be able to return arbitrary iterators (of specific item type) that may reference the original object with a lifetime 'a without having to explicitly mention 'a in the trait generics and everywhere where the trait is used or otherwise introducing significant trait bound bloat to user code. The only simple way I've figured to do this is that the trait has to be implemented for &'a MyStruct instead of MyStruct (this approach is used in some places in the standard library), but the significant drawback is that in generic code wrappers cannot “own” implementations of the trait (MyStruct) without exposing the lifetime in trait bounds all over the code. So nothing gained when ownership is needed.
Another way I figured out that should work (just done the simple test below so far) is to use higher-ranked lifetime bounds on a “base trait” that would implement the iterator-generation functions. In the code below Foo is the main trait, FooInterfaceGen is the iterator-generator trait that has its lifetime “hidden” through for <'a> when assumed as a super-trait of Foo. The FooInterface generated by FooInterfaceGen would be the trait for an appropriate type of iterator when modified to that application of the idea. However, it seems impossible to make additional trait bounds on the specific implementation FooInterfaceGen::Interface. The code below works, but when you uncomment the Asdf trait bound in the function footest, the compiler complains that
the trait `for<'a> Asdf` is not implemented for `<_ as FooInterfaceGen<'a>>::Interface
But I have implemented Asdf! It's as if the compiler is ignoring the 'a in the expression <T as FooInterfaceGen<'a>> and just applying for<'a> to the right-hand-side. Any ideas if this is a compiler bug, a known restriction, or of any ways around it?
trait FooInterface<'a> {
fn foo(&self) -> u32;
}
trait FooInterfaceGen<'a> {
type Interface : FooInterface<'a>;
fn gen(&'a self) -> Self::Interface;
}
trait Foo : for<'a> FooInterfaceGen<'a> { }
struct S2;
struct S1(S2);
impl<'a> FooInterfaceGen<'a> for S1 {
type Interface = &'a S2;
fn gen(&'a self) -> Self::Interface { &self.0 }
}
impl Foo for S1 { }
impl<'a> FooInterface<'a> for &'a S2 {
fn foo(&self) -> u32 { 42 }
}
trait Asdf {}
impl<'a> Asdf for &'a S2 {}
fn footest<T : Foo>(a : &T) -> u32
/* where for<'a> <T as FooInterfaceGen<'a>>::Interface : Asdf */ {
a.gen().foo()
}
fn main() {
let q = S1(S2);
println!("{}", footest(&q));
}
(Regarding some alternative implementations, maybe there's a technical reason for it, but otherwise I really don't understand the reason behind the significant trait bound bloat that Rust code easily introduces. Assuming a trait should in any reasonable situation automatically assume all the trait bound as well, also in generic code, not just specific code, without having to copy-paste an increasing number of where-clauses all over the code.)
The error seems to be a known compiler bug: https://github.com/rust-lang/rust/issues/89196
Suppose I have some custom collection of Foos:
struct Bar {}
struct Foo {
bar: Bar
}
struct SubList {
contents: Vec<Foo>,
}
and suppose I also have a SuperList which is a custom collection of SubLists:
struct SuperList {
contents: Vec<SubList>,
}
SubList and SuperList each provide a method bars:
impl SubList {
fn bars(&self) -> impl Iterator<Item = &Bar> + '_ {
self.contents.iter().map(|x| &x.bar)
}
}
impl SuperList {
fn bars(&self) -> impl Iterator<Item = &Bar> + '_ {
self.contents.iter().flat_map(|x| x.items())
}
}
I want to define a trait that provides a method items, and implement that trait on SubList and SuperList so that SubList::items is equivalent to SubList::bars and SuperList::items is equivalent to SuperList::bars, so that I can do this:
fn do_it<T: Buz<Bar>>(buz: &T) {
for item in buz.items() {
println!("yay!")
}
}
fn main() {
let foos = vec![Foo{ bar: Bar{} }];
let sublist = SubList{ contents: foos };
do_it(&sublist);
let superlist = SuperList{ contents: vec![sublist] };
do_it(&superlist);
}
I can do what I want with dynamic dispatch:
trait Buz<T> {
fn items(&self) -> Box<dyn Iterator<Item = &T> + '_>;
}
impl Buz<Bar> for SubList {
fn items(&self) -> Box<dyn Iterator<Item = &Bar> + '_> {
SubList::bars(self)
}
}
impl Buz<Bar> for SuperList {
fn items(&self) -> Box<dyn Iterator<Item = &Bar> + '_> {
SuperList::bars(self)
}
}
However, the following doesn't work:
trait Baz<T> {
fn items(&self) -> impl Iterator<Item = &T> + '_;
}
impl Baz<Bar> for SubList {
fn items(&self) -> impl Iterator<Item = &Bar> + '_ {
SubList::bars(self)
}
}
impl Baz<Bar> for SuperList {
fn items(&self) -> impl Iterator<Item = &Bar> + '_ {
SuperList::bars(self)
}
}
(error[E0562]: `impl Trait` not allowed outside of function and inherent method return types)
Here's a playground link to what I've tried so far
How can I define a trait Baz which provides an items method to abstract over the bars methods of SubList and SuperList without using dynamic dispatch?
Unfortunately, what you are trying to do is not really possible in Rust right now. Not by design, but simply because some relevant type level features are not implemented or stabilized yet.
Unless you have spare time, an interest in type level stuff and are willing to use nightly: just use boxed iterators. They are simple, they just work, and in most cases it will likely not even hurt performance in a meaningful way.
You're still reading? Ok let's talk about it.
As you intuitively tried, impl Trait in return type position would be the obvious solution here. But as you noticed, it doesn't work: error[E0562]: `impl Trait` not allowed outside of function and inherent method return types. Why is that? RFC 1522 says:
Initial limitations:
impl Trait may only be written within the return type of a freestanding or inherent-impl function, not in trait definitions [...] Eventually, we will want to allow the feature to be used within traits [...]
These initial limitations were put in place because the type level machinery to make this work was/is not in place yet:
One important usecase of abstract return types is to use them in trait methods.
However, there is an issue with this, namely that in combinations with generic trait methods, they are effectively equivalent to higher kinded types. Which is an issue because Rust's HKT story is not yet figured out, so any "accidental implementation" might cause unintended fallout.
The following explanation in the RFC is also worth reading.
That said, some uses of impl Trait in traits can be achieved already today: with associated types! Consider this:
trait Foo {
type Bar: Clone;
fn bar() -> Self::Bar;
}
struct A;
struct B;
impl Foo for A {
type Bar = u32;
fn bar() -> Self::Bar { 0 }
}
impl Foo for B {
type Bar = String;
fn bar() -> Self::Bar { "hello".into() }
}
This works and is "basically equivalent" to:
trait Foo {
fn bar() -> impl Clone;
}
Each impl block can choose a different return type as long as it implements a trait. So why then does impl Trait not simply desugar to an associated type? Well, let's try with your example:
trait Baz<T> {
type Iter: Iterator<Item = &Bar>;
fn items(&self) -> Self::Iter;
}
We get a missing lifetime specifier error:
4 | type Iter: Iterator<Item = &Bar>;
| ^ expected named lifetime parameter
Trying to add a lifetime parameter... we notice that we can't do that. What we need is to use the lifetime of &self here. But we can't get it at that point (in the associated type definition). This limitation is very unfortunate and is encountered in many situations (search term "streaming iterator"). The solution here are GATs: generic associated types. They allow us to write this:
trait Baz<T> {
// vvvv That's what GATs allow
type Iter<'s>: Iterator<Item = &'s Bar>;
fn items(&self) -> Self::Iter<'_>;
}
GATs are not fully implemented and certainly not stable yet. See the tracking issue.
But even with GATs, we cannot fully make your example work. That's because you use iterator types that are unnameable, due to using closures. So the impl Baz for ... blocks would not be able to provide the type Iter<'s> definition. Here we can use another feature that is not stable yet: impl Trait in type aliases!
impl Baz<Bar> for SubList {
type Iter<'s> = impl Iterator<Item = &'s Bar>;
fn items(&self) -> Self::Iter<'_> {
SubList::bars(self)
}
}
This actually works! (Again, on nightly, with these unstable features.) You can see your full, working example in this playground.
This type system work has been going on for a long time and it seems like it's slowly reaching a state of being usable. (Which I am very happy about ^_^). I expect that a few of the foundational features, or at least subsets of them, will be stabilized in the not-too-distant future. And once these are used in practice and we see how they work, more convenience features (like impl Trait in traits) will be reconsidered and stabilized. Or so I think.
Also worth noting that async fns in traits are also blocked by this, since they basically desugar into a method returning impl Future<Output = ...>. And those are also a highly requested feature.
In summary: these limitations have been a pain point for quite some time and they resurface in different practical situations (async, streaming iterator, your example, ...). I'm not involved in compiler development or language team discussions, but I kept an eye on this topic for a long time and I think we are getting close to finally resolving a lot of these issues. Certainly not in the next releases, but I see a decent chance we get some of this in the next year or two.
I have this simple snippet of code, which uses an arena for memory allocation and a trait CloneInto whose purpose is to clone a structure from unknown origins into an Arena, adjusting the lifetimes as it goes:
struct Arena;
impl Arena {
fn insert<'a, T: 'a>(&'a self, _: T) -> &'a mut T { unimplemented!() }
}
trait CloneInto<'a> {
type Output: 'a;
fn clone_into(&self, arena: &'a Arena) -> Self::Output;
}
It can be used as is:
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
struct Simple<'a> { a: &'a usize }
impl<'a, 'target> CloneInto<'target> for Simple<'a> {
type Output = Simple<'target>;
fn clone_into(&self, arena: &'target Arena) -> Simple<'target> {
Simple { a: arena.insert(*self.a) }
}
}
fn main() {
let arena = Arena;
let _ = Simple { a: &1 }.clone_into(&arena);
}
Or could, until the update to Rust 1.18. Now the compiler emits this error:
error[E0034]: multiple applicable items in scope
--> <anon>:25:30
|
25 | let _ = Simple { a: &1 }.clone_into(&arena);
| ^^^^^^^^^^ multiple `clone_into` found
|
note: candidate #1 is defined in an impl of the trait `CloneInto` for the type `Simple<'_>`
--> <anon>:18:5
|
18 | / fn clone_into(&self, arena: &'target Arena) -> Simple<'target> {
19 | | Simple { a: arena.insert(*self.a) }
20 | | }
| |_____^
= note: candidate #2 is defined in an impl of the trait `std::borrow::ToOwned` for the type `_`
even though I do not even import std or ToOwned!
This is an unfortunate effect of how method resolution works in Rust. Unlike other languages which feature overloading, in Rust the exact function to be called must be resolved unambiguously with no regard for its arguments.
In this specific case, Rust 1.18 brings a new nightly method called clone_into on the ToOwned trait, and the ToOwned trait is implemented unconditionally for all types implementing Clone and imported automatically (via the prelude).
The fact that this method cannot be called on stable has no bearing; the method is first considered for resolution, and an error will be emitted if it is actually used.
Note that even though irking, there are benefits to this method of resolution: it is often unclear to a human being which overload is selected when several appear to be available, or why the expected overload is NOT being selected. By erring on the side of explicitness, Rust makes it a no-brainer.
Unfortunately, in this case this results in Simple::clone_into() becoming ambiguous.
There is no way to opt out of the ToOwned implementation (not without giving up Clone and Copy), so instead one must switch to an unambiguous call to clone_into using Fully Qualified Syntax (FQS):
fn main() {
let arena = Arena;
let _ = CloneInto::clone_into(&Simple { a: &1 }, &arena);
}