Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implement foreign trait for foreign type [duplicate]

Tags:

rust

So I see there are reasons to forbid orphan trait implementations because of forward compatibility considerations (to prevent the addition of a further trait implementation in a library from breaking somewhere where the type's trait is used) and it possibly making compilation a lot more difficult. But I wonder which workaround would be considered by the Rust community to be the most ideal one:

(Just in case this wasn't enough background: I am trying to use rusqlite with chrono's DateTime. So I want to implement rusqlite's FromSql and ToSql traits for DateTime<UTC> but that's apparently not as easy as I thought it'd be - I'm just starting out with Rust currently.)

  • Fork rusqlite and implement the trait. (I kind of feel like this is not the nicest way to do it because maybe it's just me who needs this trait implementation there and so I might end up having to keep my own fork up to date. Also I wasn't able to implement the traits because there are some complicated generics things that I don't understand perfectly yet.)
  • Implement my own DateTime struct (probably the best workaround but I feel like this is just some replication of work that shouldn't be nescessary).
  • Somehow "copy" the DateTime<UTC> trait and give it an alias and implement the FromSql and ToSql traits for my aliased type (however I think this is not trivial either and when I tried it I wasn't able to get it to work since it was still treated as an external type).

I hope somebody can explain to me how to best solve this issue, from my pure OOP experience I would just like to be able to inherit DateTime and implement the interface but (for valid reasons) this is not how it gets done in Rust...

like image 349
evotopid Avatar asked Feb 02 '16 18:02

evotopid


2 Answers

The simplest way would be to use newtype pattern:

extern crate a;
extern crate b;

use a::SomeTrait;
use b::SomeStruct;

pub struct MySomeStruct(SomeStruct);

impl SomeTrait for MySomeStruct {
    ...
}

Here you create a wrapper around the foreign struct, and since this wrapper is a completely different type which belongs to your crate, you are free to implement a::SomeTrait for it. This is similar to your 2nd point, except that you absolutely don't need to reimplement the type from scratch.

Naturally, you won't be able to call all methods of SomeStruct on MySomeStruct. You must either forward all methods you want, or unwrap the inner value when you don't need its trait implementation anymore, or you can impl Deref for MySomeStruct { type Target = SomeStruct; ... }, but the latter is considered an antipattern.

like image 143
Vladimir Matveev Avatar answered Nov 05 '22 02:11

Vladimir Matveev


I'm not sure what would be the most idiomatic, but it looks like the best approach would be to use the newtype pattern, which is a tuple-struct with one field. This creates a new type distinct from the old one, and you can implement the traits for that new type. To use the trait methods, you will need to wrap it in the newtype, but to use the normal methods, you'll use the normal struct without your newtype wrapper.

struct MyType(TheirType);

impl TheTrait for MyType {
    ....
}

fn main() {
    let a = TheirType::new(....);
    a.method_on_their_type();
    let b = MyType(TheirType::new(....));
    b.method_on_the_trait();
}
like image 37
Alex Knauth Avatar answered Nov 05 '22 02:11

Alex Knauth