I was playing around the visitor design pattern in Rust. My initial visitor didn't have any type parameter so I was able to do something like this:
impl<T> From<T> for Box<dyn VisitorElement>
where
T: VisitorElement + 'static,
{
fn from(elem: T) -> Box<dyn VisitorElement> {
Box::new(elem)
}
}
As my visitor was simply a f32
calculator, I wanted to make it more generic by replacing f32
by a type parameter. After passing the proper type parameter everywhere, my From
implementation wouldn't work. Here's a complete example (playground):
/*
* Visitor traits
*/
trait Visitor<T> {
fn visit_literal(&mut self, literal: &Literal<T>);
}
trait VisitorElement<T> {
fn accept(&self, visitor: &mut dyn Visitor<T>);
}
/*
* Literal value
*/
struct Literal<T> {
value: T,
}
impl<T> Literal<T> {
fn new(value: T) -> Self {
Self { value: value }
}
}
impl<T> VisitorElement<T> for Literal<T> {
fn accept(&self, visitor: &mut dyn Visitor<T>) {
visitor.visit_literal(self)
}
}
impl<K, T> From<K> for Box<dyn VisitorElement<T>>
where
K: VisitorElement<T> + 'static,
{
fn from(elem: K) -> Box<dyn VisitorElement<T>> {
Box::new(elem)
}
}
fn main() {
let element = Literal::new(0.1);
let boxed: Box<dyn VisitorElement<_>> = element.into();
}
error[E0119]: conflicting implementations of trait `std::convert::From<std::boxed::Box<(dyn VisitorElement<_> + 'static)>>` for type `std::boxed::Box<(dyn VisitorElement<_> + 'static)>`:
--> src/main.rs:28:1
|
28 | / impl<K, T> From<K> for Box<dyn VisitorElement<T>>
29 | | where
30 | | K: VisitorElement<T> + 'static,
31 | | {
... |
34 | | }
35 | | }
| |_^
|
= note: conflicting implementation in crate `core`:
- impl<T> std::convert::From<T> for T;
= note: downstream crates may implement trait `VisitorElement<_>` for type `std::boxed::Box<(dyn VisitorElement<_> + 'static)>`
My goal was to allow auto boxing dynamic types in order to make code typing less verbose.
From How is there a conflicting implementation of `From` when using a generic type?, I can see that the type S
can cause the trait to convert to itself but in my case the type K
is constrained to VisitorElement
but I stille end up with a conflict with a Box<dyn VisitorElement<_> + 'static>
.
Is there a reason why the constraint on K: VisitorElement<T> + 'static
allows a Box<dyn VisitorElement<T> + 'static>
into itself but K: VisitorElement<f32>
doesn't?
From my understanding, the type K
can't be a Box
because Box
doesn't implement VisitorElement<T>
, so I should never end up with a Box as K
.
If the issue was caused by the Into
being automatically implemented... I'd have From> for Literal<_>
then Literal<_>
into Box<dyn VisitorElement<_>
, but that's true for any type. In my case it doesn't explicitly do that, unless the Box
is a special type that implements the same trait as its content?