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.)
DateTime
struct (probably the best workaround but I feel like this is just some replication of work that shouldn't be nescessary).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...
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.
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();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With