3

I have this issue:

  • multiple structs implementing a trait Event
  • all can implement PartialEq trait the same way

I considered writing this (short version)

type Data = Vec<u8>;

trait Event {
    fn data(&self) -> &Data;
}

struct NoteOn {
    data: Data,
}
struct NoteOff {
    data: Data,
}
impl Event for NoteOn {
    fn data(&self) -> &Data {
        &self.data
    }
}
impl Event for NoteOff {
    fn data(&self) -> &Data {
        &self.data
    }
}
impl<T: Event> PartialEq for T {
    fn eq(&self, b: &T) -> bool {
        self.data() == b.data()
    }
}

fn main() {
    println!("Hello, world!");
}

playground

This fails to compile:

error[E0119]: conflicting implementations of trait `std::cmp::PartialEq<&_>` for type `&_`:
  --> src/main.rs:23:1
   |
23 | impl<T: Event> PartialEq for T {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: conflicting implementation in crate `core`:
           - impl<A, B> std::cmp::PartialEq<&B> for &A
             where A: std::cmp::PartialEq<B>, A: ?Sized, B: ?Sized;
   = note: downstream crates may implement trait `Event` for type `&_`

error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
  --> src/main.rs:23:1
   |
23 | impl<T: Event> PartialEq for T {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type
   |
   = note: only traits defined in the current crate can be implemented for a type parameter

What is wrong here? Or is there another way to implement generically this PartialEq without having to type it once for NoteOn and once for Noteff?

thank you

dzada
  • 5,344
  • 5
  • 29
  • 37
  • It looks like your question might be answered by the answers of [I implemented a trait for another trait but cannot call methods from both traits](https://stackoverflow.com/q/29256519/155423). If not, please **[edit]** your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Jul 30 '19 at 15:13
  • Making more guesses about what your failure is, your question may be answered by the answers of [How is there a conflicting implementation of `From` when using a generic type?](https://stackoverflow.com/q/37347311/155423). If not, please **[edit]** your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Jul 30 '19 at 15:34
  • Perhaps you could explain what you don't understand about the compiler's help messages? – Shepmaster Jul 30 '19 at 17:52
  • @Shepmaster Thank you for your comments, I made a playground example and compile-able example (no crate needed). The issues is a Conflict, although the error message: T must be used in Local type makes little sens to me as T is used as a local type. thanks again – dzada Jul 30 '19 at 17:53
  • Currently, this is a dupe of [How do I implement a trait I don't own for a type I don't own?](https://stackoverflow.com/q/25413201/3650362) (answer: you don't, but there are workarounds). More broadly, I think your problem is addressed by one or both of [How do I make many different structs that all implement the same trait comparable to each other?](https://stackoverflow.com/q/51966865/3650362) and [How to test for equality between trait objects?](https://stackoverflow.com/q/25339603/3650362) (be sure to read *all* the answers). – trent Jul 30 '19 at 18:27
  • You may want to use [`enum`, instead of a trait](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=a2ea6132f512b43052bda6eb9734726f) or [implement `PartialEq` for the trait object type](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=64c505d3444e3785ac54eea384a0db09). – trent Jul 30 '19 at 18:30
  • @trentcl I do not think this is a duplicate of https://stackoverflow.com/q/25413201/3650362, as i own that trait (Event). I would say it does look more like https://stackoverflow.com/q/51966865/3650362 but if i understand what is written in that post the answer to my question is This is not possible in rust – dzada Jul 30 '19 at 18:37
  • @trentcl thank you for your suggestion about Enum and for the usage of dyn; I will have to add that if the actual type of Event (NoteOn, NoteOff) is different, it should return false. The suggestion with the usage of Enum does not match my need really as I have in the actual implementation not shortened other attributes in this structs. So I guess I will see how to workaround the issue – dzada Jul 30 '19 at 18:41
  • `Event` is not relevant; you don't own `PartialEq` or `T` (for some hypothetical `T`), so you can't implement `PartialEq` for `T`. – trent Jul 30 '19 at 18:50
  • I understand that, @trentcl thank you. About dyn too, This code shoud be not dynamic and generate the PartialEq for each type implementing Event but should in anyway require dynamic dispatch of the type, as this would just mean i should type both implementation manually. – dzada Jul 30 '19 at 18:52

1 Answers1

1

Here is my best "attempt" at a possible way to do what i wanted, but in a different way following the remarks from @trentcl and @Shepmaster.

I used an Enum as mentioned by @trentctl to be able to switch between the different types, I keep the enum value within a common struct Event so I can easily wrap the different objects and add more code to the Event. Doing this also helps to make an easy Vec type.

Here i imagine that i only need the Enum, and not Event and an attribute with the enum, I am still learning the variant enum usage

I also had issues mentioned by @trentcl about the fact i did not own the Vec type, so i wrapped the Vec in a struct Sec instead of simply aliasing the type. This makes my implementation of PartialEq seperated from the type Vec (if i understand, but i m not sure) => the reason i am troubled here is that I thought that using type A = B;did create a new type, but the documentation does state it s aliasing (which could make send to why i m not able to implement PartialEq for Vec) although in the end I imagine i may be very wrong on that too as the fact i created an artificial struct to just wrap 1 attribute also seems counter productive

=> So to conclude for now thank you everyone, I will keep working on this to see how it could be more efficient, but I guess I was simply using the wrong stuff for the context of Rust, I am not sure this is a good answer and would appreciate feedbacks or other suggestions.

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d67b7d993fa6b6285962ee58e9b215e5

type Data = Vec<u8>;

#[derive(Debug)]
enum EventImpl{
    NoteOn(u8),
    NoteOff(u8)
}
#[derive(Debug)]
struct Event{
    data:Data,
    i:EventImpl
}

impl Event{
    fn new(data:Data)->Self{
        Event{
            i: match data[0]{
                0 => EventImpl::NoteOn(data[1]),
                1 => EventImpl::NoteOff(data[1]),
                _ => panic!("unk")
            },
            data:data
        }
    }

    fn data(&self)->&Data{
        &self.data
    }
}
#[derive(Debug)]
struct Seq{
    pub things:Vec<Event>
}

impl PartialEq for Seq{
    fn eq(&self,o:&Self)->bool{
    // i have to learn the iterator implementation    
        let mut r=o.things.len()==self.things.len();
        if ! r{
            return false;
        }
        for i in 0..o.things.len() {
            r = r && o.things[i]==self.things[i];
        }
        r
    }
}
impl PartialEq for Event{
    fn eq(&self,o:&Self)->bool{
    // i have to learn the iterator implementation    
        std::mem::discriminant(&self.i) == std::mem::discriminant(&o.i) && o.data()==self.data()
    }
}


fn main() {
    let mut s:Seq=Seq{things:vec![Event::new(vec![1,2,3])]};
    s.things.push(Event::new(vec![0,1,2]));
    let s2:Seq=Seq{things:vec![Event::new(vec![1,2,3]),Event::new(vec![0,1,2])]};

    println!("Hello, world! {:?} {:?}",s, s.things[1].data());
    println!("S1 == S2 ? {}",s==s2);
}

dzada
  • 5,344
  • 5
  • 29
  • 37