How to have a vec of Boxes which implement 2 traits? [duplicate] - rust

This question already has an answer here:
Can I get a trait object of a multi-trait instance without using a generic type?
(1 answer)
Closed 10 months ago.
In rust I would like to have a vec containing items which implement 2 traits. However when I try to implement it like so, I get the error only auto traits can be used as additional traits in a trait object:
let mut v : Vec<Box<dyn MyTrait + std::fmt::Display>> = Vec::new();
FairPlay, I read the error message in full and defined a Trait which combines the two:
pub trait FormattableDoer: std::fmt::Display + MyTrait{}
The have a Vec of Boxes to that:
let mut v: Vec<Box<dyn FormattableDoer>> = Vec::new();
However the compiler can't seem to detect that my struct has implemented those things separately and I get the error the trait bound MyStruct: FormattableDoer is not satisfied.
I read about using a trait alias, but that's not in stable so I'd rather not use it.
Is this possible in rust? It seems like a common thing to want to do and I'm surprised that the answer isn't simple (or maybe it is and I have missed it!). I'm also thinking that maybe I have approached the problem all wrong and I'm attempting to do something in an 'non rusty' way. If that's the case, what is the preferred way of having a vector of things which are displayable and have some other trait?
Playground with a MWE and a use case.

You're almost there. You need a marker trait that implements both parents, as you've already done
pub trait FormattableDoer: std::fmt::Display + MyTrait {}
Then you need a blanket implementation which takes those two traits to your new trait.
impl<T: std::fmt::Display + MyTrait> FormattableDoer for T {}
Now everything that implements std::fmt::Display and MyTrait will implement FormattableDoer automatically, and since FormattableDoer is a single trait, it can be used as a trait object.
Then just use Box<dyn FormattableDoer> like you've already tried.

You still need to implement FormattableDoer for your struct. In the playground you posted, you're not doing that. Simply add
impl FormattableDoer for MyStruct {}
and you should be all done.
No user-defined traits are auto-implemented, even if they contain no methods or associated types.

Related

Re-implement Debug trait for a third-party struct in Rust

I have an autogenerated struct named Address by protobuf in Rust. It has a predefined Debug trait like this:
impl ::std::fmt::Debug for Address {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f)
}
}
But I want to customize how it's printed when {:#?} is used. So I decided to implement Debug trait for it like this in my project:
impl fmt::Debug for EvmProto::Address {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
....
}
}
But it complains that conflicting implementations of trait `std::fmt::Debug` for type `protos::Evm::Address
UPDATE: while the answer can still be useful in some similar cases, in this case it seems incorrect. See the comments for details.
You can't implement an external trait on an external type.
I'm citing The Rust Book
we can’t implement external traits on external types. For example, we can’t implement the Display trait on Vec<T> within our aggregator crate, because Display and Vec<T> are both defined in the standard library and aren’t local to our aggregator crate. This restriction is part of a property called coherence, and more specifically the orphan rule, so named because the parent type is not present. This rule ensures that other people’s code can’t break your code and vice versa. Without the rule, two crates could implement the same trait for the same type, and Rust wouldn’t know which implementation to use.

Why using boxed objects over trait objects?

In the book Rust for Rustaceans, the author writes:
Broadly speaking, though, you’ll want to use static dispatch in your libraries and dynamic dispatch in your binaries. In a library, you want to allow your users to decide what kind of dispatch is best for them, since you don’t know what their needs are.
I guess that, in the binary case, he refers to this:
fn flexible_dispatch_method(_: &dyn MyTrait) {}
// static dispatch
//
let obj = MyType {};
flexible_dispatch_method(&obj);
// dynamic dispatch
//
let trait_obj: &dyn MyTrait = &MyType {};
flexible_dispatch_method(trait_obj);
Given the above, what's the advantage of using boxed objects instead of trait objects? Is it because of the need to use lifetimes:
fn return_new_trait_object<'a>() -> &'a dyn MyTrait {
&MyType {}
}
or there is something else? Based on my understanding, in the dynamic dispatch case, the object needs to be allocated in the heap, anyway, so I presume there isn't much difference with a boxed object.
I think you might be misunderstanding a couple things here.
(Generally) static dispatch occurs whenever you call a method on a concrete type that's not dyn Trait. It's when the compiler decides which function to call at compile-time.
A trait object is anything that's some pointer to a dyn Trait, including Box<dyn Trait>, &dyn Trait, Arc<dyn Trait>, etc. When you call a function through a dyn Trait, the compiler inserts code to lookup the function to call at runtime, allowing for polymorphism and greater flexibility.
In your code, flexible_dispatch_method(_: &dyn MyTrait) always uses dynamic dispatch, as signaled by the fact that its argument has the type &dyn MyTrait. An example of static dispatch would be the following:
fn flexible_dispatch_method<T: MyTrait + ?Sized>(_: &T) {}
With this declaration your first usage would use static dispatch and the second would use dynamic dispatch.
Dynamic dispatch is a little more flexible since it avoids having generics all over the place. This can be useful for writing large applications where you might want to have polymorphism and easily add new implementations. However, dynamic dispatch has a performance cost, so that's why libraries should leave the dispatch choice up to the caller as much as possible.
As per when to use &dyn Trait vs Box<dyn Trait>: it's all based on ownership. If you want an owned trait object use Box<dyn Trait>, and if you want a borrowed trait object use &dyn Trait.

Why is std::borrow::Borrow not implementet for every Type?

On the documentation it is stated that
impl<T> Borrow<T> for T where
T: ?Sized,
I would read this:
This Trait is implemented for every Type, even unsized ones.
Is this correct?
I got the error message:
the trait std::borrow::Borrow<T> is not implemented for &num_complex::Complex<f64>
which I can't make sense of.
(I do not want to post the whole code, I just want some clarification about which types implement std::borror::Borrow)
The important thing to recognize is that in the blanket impl there is only one T and it has to represent the same type in both places:
impl<T> Borrow<T> for T
where T: ?Sized
implements for each type T, only the specific trait Borrow<T>. i64 implements Borrow<i64>, String implements Borrow<String>, etc. When we instantiate this with T = &num_complex::Complex<f64>, what trait is implemented?
impl Borrow<&num_complex::Complex<f64>> for &num_complex::Complex<f64> // (not compilable code, just illustrative)
In words, you can borrow a &Complex<f64> as a &Complex<f64>, but you can't borrow it as any arbitrary T (which wouldn't make much sense, anyway).
You're using this in some generic code where T can be anything, so the blanket impl of Borrow<T> for T doesn't apply. You can probably fix this by adding a trait bound:
where num_complex::Complex<f64>: Borrow<T>
which means that Complex<f64> itself implements Borrow<T>, or
where for<'a> &'a num_complex::Complex<f64>: Borrow<T>
which means that any reference to Complex<f64> implements Borrow<T>. Depending on your actual code either or both of these may work due to autoref/autoderef.

Implement From on a trait which has Self as member

I want to be able to convert any iterator into MyType.
impl<T, I: IntoIterator<Item = T>> From<I> for MyType<T>
As in
MyType<T>::from<I: IntoIterator>(iter: I) -> MyType<T>
As one expects, it makes sense for MyType to itself be convertible to an Iterator and satisfy IntoIterator as a trait, and it does.
But From is automatically implemented reflexively for any type, any type can convert into itself of course, and this is where the compiler barks:
error[E0119]: conflicting implementations of trait
`std::convert::From<MyType<_>>` for type `MyType<_>`:
My generic implementation for all IntoIterators conflicts with the default one. If Rust did not provide a default one then it would actually work albeit being needlessly expensive.
Is there any way to implement the trait for any member of IntoIterator except MyType?
There is actually a precedent in the Rust standard library: Iterator::collect is about creating a new value from an iterator.
Following this model, rather than implementing std::convert::From, you should implement std::iter::FromIterator.
And then there will be no conflict.

Is there a way other than traits to add methods to a type I don't own?

I'm trying to extend the Grid struct from the piston-2dgraphics library. There's no method for getting the location on the window of a particular cell, so I implemented a trait to calculate that for me. Then, I wanted a method to calculate the neighbours of a particular cell on the grid, so I implemented another trait.
Something about this is ugly and feels unnecessary seeing as how I'll likely never use these traits for anything other than this specific grid structure. Is there another way in Rust to extend a type without having to implement traits each time?
As of Rust 1.67, no, there is no other way. It's not possible to define inherent methods on a type defined in another crate.
You can define your own trait with the methods you need, then implement that trait for an external type. This pattern is known as extension traits. The name of extension traits, by convention, ends with Ext, to indicate that this trait is not meant to be used as a generic bound or as a trait object. There are a few examples in the standard library.
trait DoubleExt {
fn double(&self) -> Self;
}
impl DoubleExt for i32 {
fn double(&self) -> Self {
*self * 2
}
}
fn main() {
let a = 42;
println!("{}", 42.double());
}
Other libraries can also export extension traits (example: byteorder). However, as for any other trait, you need to bring the trait's methods in scope with use SomethingExt;.
No. Currently, the only way to write new methods for a type that has been defined in another crate is through traits. However, this seems too cumbersome as you have to write both the trait definition and the implementation.
In my opinion, the way to go is to use free functions instead of methods. This would at least avoid the duplication caused by traits.

Resources