0

What are some general strategies for resolving trait implementations when using generics in Rust? As a contrived example, consider the following code that allows conversion from primitive types to a struct:

// External libraries
use std::fmt::Debug;

// Create some structure that we can convert from and into
#[derive(Debug)]
struct MyStruct <T> {
    val : T,
}

// Convert from a value
trait ConvertFrom <T>
where
    Self : Sized
{
    fn from(t : T) ->  Self;
}

// Convert T into a T
impl <T> ConvertFrom <T> for T {
    fn from(t : T) -> Self {
        t
    }
}

// Convert f32 into f64
impl ConvertFrom <f32> for f64 {
    fn from(t : f32) -> Self {
        t as f64 
    }
}

// Convert T into a MyStruct <U>
impl <T,U> ConvertFrom <T> for MyStruct <U>  
where
    U : ConvertFrom <T>
{
    fn from(t : T) -> Self {
        MyStruct{ val : ConvertFrom::<T>::from(t) }
    }
}  

// Test our conversion
fn foo01 <T> () -> ()
where
    T : ConvertFrom <f32> + Debug
{
    let y01 : T = ConvertFrom::<f32>::from(1.2_f32);
    println!("{:?}",y01);
}

fn main() {
    foo01::<MyStruct<f32>>();  
    foo01::<f64>();
}

This gives the compiler error:

error[E0119]: conflicting implementations of trait `ConvertFrom<MyStruct<_>>` for type `MyStruct<_>`:
  --> src/test03.rs:33:1
   |
19 |   impl <T> ConvertFrom <T> for T {
   |   ------------------------------ first implementation here
...
33 | / impl <T,U> ConvertFrom <T> for MyStruct <U>
34 | | where
35 | |     U : ConvertFrom <T>
36 | | {
...  |
39 | |     }
40 | | }
   | |_^ conflicting implementation for `MyStruct<_>`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0119`.
error: Could not compile `rust_from_to`

This makes sense, there's an ambiguity between the identity conversion from T->T and from T->MyStruct <U> since T could be something like MyStruct<f32> and U could be f32. What's not clear to me is how to resolve it and rustc --explain E0119 did not give great hints. At issue is that I'd like to have a conversion function that converts T into MyStruct <U> whenever T converts to U. I can make this work if T=U with the trait:

// Convert T into a MyStruct <T>
impl <T> ConvertFrom <T> for MyStruct <T> {
    fn from(t : T) -> Self {
        MyStruct{ val : t }                        
    }
}  

but this is less general than I'd like. Is there a general strategy for constructing such traits or functions?

wyer33
  • 6,060
  • 4
  • 23
  • 53
  • 1
    You may find the [marker structs + extra parameter](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=6a74e5d5a8133e478898dcedf0162b11) idea as described in [this answer](https://stackoverflow.com/a/52692592/3650362) to be useful. Might that answer your question? There are definitely drawbacks, like the proliferation of generics. – trent Sep 20 '19 at 01:34
  • 1
    AFAIK there is no simple solution today. [RFC 1210](https://github.com/rust-lang/rfcs/blob/master/text/1210-impl-specialization.md) aims to solve this once it is implemented. – Jmb Sep 20 '19 at 06:24
  • I don't believe specialization can fix this; you still have a coherence issue because any downstream can `struct Quux; impl ConvertFrom> for Quux` and neither `impl` in the example is more specific. – trent Sep 20 '19 at 11:18

0 Answers0