Here is some simplified example code. It gives an error:
error[E0119]: conflicting implementations of trait `HasWidgetId` for type `Box<_>`
--> src/lib.rs:22:1
|
11 | impl<W: HasWidgetId> HasWidgetId for Box<W> {
| ------------------------------------------- first implementation here
...
22 | impl<W: Widget> HasWidgetId for W {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<_>`
|
= note: downstream crates may implement trait `Widget` for type `std::boxed::Box<_>`
For more information about this error, try `rustc --explain E0119`.
error: could not compile `playground` (lib) due to 1 previous error
I'm trying to say that Widgets have widget IDs, and also anything Boxed that implements the trait, also implements the trait. I guess I've gone astray in my thinking here, but don't know where.
Here's the code from the playground linked above:
use std::any::Any;
type WidgetId = i32;
pub trait HasWidgetId {
fn widget_id(&self) -> WidgetId;
}
impl HasWidgetId for WidgetId {
fn widget_id(&self) -> WidgetId { *self }
}
impl<W: HasWidgetId> HasWidgetId for Box<W> {
fn widget_id(&self) -> WidgetId {
let id = self.widget_id();
id
}
}
impl<T: HasWidgetId + ?Sized> HasWidgetId for &T {
fn widget_id(&self) -> WidgetId {
(*self).widget_id()
}
}
impl<W: Widget> HasWidgetId for W {
fn widget_id(&self) -> WidgetId {
self.id()
}
}
pub trait Widget : Any {
fn as_any(&self) -> &dyn Any;
fn id(&self) -> WidgetId;
}
It is possible to implement Widget for a type Box<LocalType> and at the same time implement HasWidgetId for LocalType. If you do that, these two implementations would overlap.
In your implementation, is the id method on the Widget trait needed? It seems like that is the same as impl HasWidgetId. If you impl HasWidgetId instead to get the id, then I think you wouldn't need the blanket impl impl<W: Widget> HasWidgetId for W which is causing the overlapping implementations.
I don't think I follow this. Do you mean for every type that I want to make a Widget, I would also make it a HasWidgetId?
struct Foo;
impl Widget for Foo { ... }
impl HasWidgetId for Foo { ... }
I was trying to avoid repeating myself like that.
I think I started with just Widget and then I realized I wanted some generic functions to take either a Widget or an ID. So I tried to make that trait HasWidgetId to encompass them both.
I'm thinking if you're already implementing Widget for some T, you have to implement the id trait method. That seems equivalent to directly implementing the HasWidgetId for T and removing the id trait method.
when it comes to coherence, there's a special rule, that says the T in Box<T> is uncovered, because Box is a fundamental type constructor.
also note, references are fundamental type constructors too, so your other impl will also be rejected (but in this particular example, the compiler stopped at the first error, so it didn't report this one):
all this means is, if you want to add blanket implementation for fundamental types such as Box<T>, &T, etc, you cannot have a blanket implementation for T.