Implement TraitA for all types that implement TraitB - rust

I am trying to understand why the following code does not compile:
trait Vehicle {
fn get_num_wheels(&self) -> u32;
}
impl std::fmt::Display for dyn Vehicle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Has {} wheels", self.get_num_wheels())
}
}
struct Car();
impl Vehicle for Car {
fn get_num_wheels(&self) -> u32 {
4
}
}
fn main() {
let car = Car {};
println!("{car}");
}
error[E0277]: `Car` doesn't implement `std::fmt::Display`
--> src/main.rs:21:16
|
21 | println!("{car}");
| ^^^ `Car` cannot be formatted with the default formatter
|
= help: the trait `std::fmt::Display` is not implemented for `Car`
I would think that if I implemented Display for Vehicle, then all structs that implement Vehicle would also inherit Vehicle's implementation of Display. I can see why this would be an issue if Car tried to make its own implementation of Display, but this is not the case here.
I know I can fix this example by changing
impl std::fmt::Display for dyn Vehicle
to
impl std::fmt::Display for Car
but for non-trivial examples, this seems really verbose. What's the right way to do this?

The type dyn Vehichle is not the same as the trait Vehichle. Specifically, it's what's called a trait object, and can hold a value of any type that implements the trait.
Therefore, when you implement Display for dyn Vehichle, you only implement it for that particular type, but not for any other type that implements the trait.
If you want every type that implements a trait TraitA (e.g. Vehicle) to also implement a trait TraitB (e.g. Display), there are two ways of approaching this, each with some caveats.
The first is to have a blanket implementation. Due to the orphan rule, this can only be done if TraitB is defined in the same crate, so this wouldn't work with Display which is defined in the standard library.
impl<T: TraitA> TraitB for T {
// ...
}
The second approach is to declare TraitB a supertrait of TraitA. This will work even if TraitB is not defined in the same crate, however this will require any trait that implements TraitA to also implement TraitB, which again due to the orphan rule may not be possible for types that are not defined in the same crate.
trait TraitA: TraitB {
// ...
}
impl TraitA for SomeType {}
// required by the above, else the compiler will complain
impl TraitB for SomeType {}
In either case, you will not be able to implement a trait from a different crate, such as Display, on a type from a different crate. The first approach won't work for your code, but the second can work since the Car type is defined in the same crate.
An approach to circumvent the issue entirely is instead to have a "displayable wrapper type" that can wrap any type that implements Vehicle. For example:
struct DisplayVehicle<'a, V: ?Sized + Vehicle>(&'a V);
impl<'a, V: ?Sized + Vehicle> std::fmt::Display for DisplayVehicle<'a, V> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Has {} wheels", self.0.get_num_wheels())
}
}
fn main() {
let car = Car {};
println!("{}", DisplayVehicle(&car));
}
(Playground link)
While this does become slightly more verbose, it avoids the orphan rule entirely and therefore doesn't have the same issues as trying to implement Display directly on every Vehicle type. Additionally, since the Display implementation isn't actually related to the type itself but to the trait, this may be generally a more idiomatic approach to the solve this problem.

It works if you cast directly to the trait object btw:
trait Vehicle {
fn get_num_wheels(&self) -> u32;
}
impl std::fmt::Display for dyn Vehicle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Has {} wheels", self.get_num_wheels())
}
}
struct Car();
impl Vehicle for Car {
fn get_num_wheels(&self) -> u32 {
4
}
}
fn main() {
let car = Car {};
println!("{}", &car as &dyn Vehicle);
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=34f17655e85b3039c327846f5b8a9568

Related

How to return a box to self?

I'm new to rust and I experience difficulties to develop my personal first project.
To get the essential my code looks like this:
pub trait MyTrait {
type Out: MyTrait;
fn foo(&self) -> Box<Self::Out>;
}
pub struct MyStruct<T: MyTrait>(Box<T>);
impl<T: MyTrait> MyTrait for MyStruct<T> {
type Out = Self <>;
fn foo(&self) -> Box<Self::Out> {
Box::new(self)
}
}
The error message I get is :
expected struct MyStruct<T> found reference &MyStruct<T>
I tried many things but I can't find how to return a box to self...
I have another question: actually MyTrait extends another trait and I have many struct that implement MyTrait so in my code I have many impl, one for each trait by struct and I find it really verbose, isn't it possible to implement all methods (from a trait and all its parents) at once (like in java) ? Or is there syntactic sugar to implement methods with closures ?
Thanks
Box needs to own self. You cannot pass a reference into it, it has to be the actual self object.
This works:
pub trait MyTrait {
type Out: MyTrait;
fn foo(self) -> Box<Self::Out>;
}
pub struct MyStruct<T: MyTrait>(Box<T>);
impl<T: MyTrait> MyTrait for MyStruct<T> {
type Out = Self;
fn foo(self) -> Box<Self::Out> {
Box::new(self)
}
}
Further remarks:
I'm unsure why you need that function, but it seems to me like you are trying to downcast from a boxed dyn trait to an actual type.
Sadly, this won't work this way. It's impossible for the compiler to figure out which type was the original type if your Box<dyn MyTrait> doesn't contain that information any more. That's why you need the Out associated type here, but you probably didn't yet realize that this means you can no longer store a Box<dyn MyTrait> object. It's now a Box<dyn MyTrait<Out = MyStruct>> object, which cannot be mixed with other MyTrait types any more.
If you really want to achieve that, there are several options. RTTI is one option, with the Any trait.
Another one would be a Visitor pattern, which could resolve this:
pub trait Visitor {
fn visit_mystruct(&mut self, s: &mut MyStruct);
}
pub struct MyVisitor;
impl Visitor for MyVisitor {
fn visit_mystruct(&mut self, s: &mut MyStruct) {
println!("Visited MyStruct: {:?}", s.0);
}
}
pub trait MyTrait {
fn visit(&mut self, visitor: &mut dyn Visitor);
}
pub struct MyStruct(i32);
impl MyTrait for MyStruct {
fn visit(&mut self, visitor: &mut dyn Visitor) {
visitor.visit_mystruct(self);
}
}
fn main() {
let mut obj: Box<dyn MyTrait> = Box::new(MyStruct(42)) as Box<dyn MyTrait>;
let mut visitor = MyVisitor;
// Here is no information any more about the actual type of `obj`.
// Visitor gets the type resolved again
obj.visit(&mut visitor);
}
Visited MyStruct: 42
A visitor pattern is especially useful in cases like tree structures, because it can be recursively applied to children. It is commonly used in compilers.
Another alternative would be to use an Enum instead of a Box<dyn Trait>.
Although those are all just based on assumptions now.

How to create a factory method in rust to return generic container - getting an error "doesn't have a size known at compile-time" returning generic

I have a container type like this:
struct Container<T: Sized + MyTrait + Serialize> {
data: T,
key: String
}
wrapping this trait:
trait MyTrait {
fn do_something(&self) -> Something;
}
I have many concrete implementors of MyTrait:
struct S1 {}
impl MyTrait for S1 { ... };
... many kinds ...
struct S10{}
impl MyTrait for S10 { ... }
I have a higher level which should vend the appropriate implementation based on some decision logic (a factory of MyTrait types):
fn get_appropriate_impl(type_of_instance: SomeEnum ... ) -> Container<MyTrait> {
...choose appropriate implementation to return...
return match type_of_instance {
// each branch should return a different type
}
}
I get an error
Container<MyTrait> {
doesn't have a size known at compile-time
I've tried many variations:
Container<Box<MyTrait>>
Box<Container<MyTrait>>
Box<Container<Box<MyTrait>>
each has their own errors
How do I resolve this?
PS - I've also implemented Deref and DerefMut on Container:
impl<T: MyTrait > Deref for Container<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.data
}
}
You are trying to return a trait, not an object. The size of an implementation of a trait is not known at compile time (imagine, you implement MyTrait for u8 and u16, what size the return type would have?). The Sized bound does not help here (and it's implicit, too), because it only requires that T is Sized, but not MyTrait. Also, adding a bound to MyTrait: Sized does not help because it only requires, that the object, you implement MyTrait for, is sized, but it does not specify which size it may have.
This can be solved by either returning a concrete type, which is implementing MyTrait or wrapping the trait (e.g. in a Box). You are probably looking for the latter approach.
Returning a concrete type can be either done by adding a generic argument to the function:
fn get_appropriate_impl<T: MyTrait>() -> Container<T> {
...
}
or by using the impl Trait notation:
fn get_appropriate_impl() -> Container<impl MyTrait> {
...
}
However, if you don't know the return type beforehand, you probably want to store the object on the heap and return a pointer to that, e.g. by using Box, Rc, or Arc:
fn get_appropriate_impl() -> Container<Box<dyn MyTrait>> {
...
}
This requires you to implement MyTrait on Box<dyn MyTrait> as well, this can be done by implementing it on Box yourself:
impl MyTrait for Box<dyn MyTrait> {
fn do_something(&self) -> Something {
(**self).do_something()
}
}
If you know that you will only use Box for Container<T> you might want to encapsulate it there directly:
struct Container {
data: Box<dyn MyTrait>,
}

`AsArray` cannot be made into an object when implementing a trait for a trait

Basically I'm trying to make a trait that indicates the ability to be converted into a 2D ndarray aka ndarray::Array2:
trait Into2DArray{
fn to_array(&self) -> Array2<f64>;
}
I would like to do this by expanding the existing AsArray trait, but Rust forbids me from implementing a third party trait for a third party struct (polars::DataFrame) for some esoteric reason, so instead I have to make my own trait for this.
Anyway, this works well for polars::DataFrame:
impl Into2DArray for DataFrame {
fn to_array(&self) -> Array2<f64> {
return self.to_array();
}
}
However, I also want to implement this for anything that is already convertable into a 2D array, so I implement this trait for the AsArray trait mentioned above:
impl Into2DArray for AsArray<'_, f64, Ix2> {
fn to_array(&self) -> Array2<f64> {
return self.into();
}
}
However the compiler gives me grief for this:
|
26 | impl Into2DArray for AsArray<'_, f64, Ix2> {
| ^^^^^^^^^^^^^^^^^^^^^ `AsArray` cannot be made into an object
|
= note: the trait cannot be made into an object because it requires `Self: Sized`
= note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
I understand that has something to do with object safety but I thought I had fulfilled all the criteria mentioned on that page, namely the trait doesn't return Self, and all the generic parameters of AsArray are specified.
What is going wrong, and how can I fix it?
What you were trying to do is implementing the Into2DArray trait for the AsArray dynamic trait object. There should have been a warning of using AsArray without dyn anyway.
But this is not what you actually want. You want to implement it for any type that implements AsArray. Just like you did in your comment.
It is important to know the difference between these two things:
trait NeedThis {
fn can_be_called_by_the_impl(&self) {}
}
trait ToDoThis {
fn example(&self);
}
impl ToDoThis for dyn NeedThis {
fn example(&self) {
self.can_be_called_by_the_impl()
}
}
impl NeedThis for u8 {}
fn main() {
let num: u8 = 0;
// num.example(); // doesn't work because ToDoThis is not implemented for u8
let num_as_trait_obj: &dyn NeedThis = &0_u8 as &dyn NeedThis;
num_as_trait_obj.example(); // works because this time it is a trait object
}
trait NeedThis {
fn can_be_called_by_the_impl(&self) {}
}
trait ToDoThis {
fn example(&self);
}
// removing ?Sized would make it the same as T: NeedThis + Sized
impl<T: NeedThis + ?Sized> ToDoThis for T {
fn example(&self) {
self.can_be_called_by_the_impl()
}
}
impl NeedThis for u8 {}
fn main() {
let num: u8 = 0_u8;
num.example(); // works because we implemented it for all types that implement NeedThis
let num_as_trait_obj: &dyn NeedThis = &0_u8 as &dyn NeedThis;
num_as_trait_obj.example(); // works because dyn NeedThis also implements NeedThis.
// This is only true because we added ?Sized to the bounds of the impl block.
// Otherwise it doesn't work because dyn NeedThis is not actually Sized.
// And a Sized bound is implied by default.
}

implementing traits for dyn Fns

Today I was playing around with function traits. Though the example I show below might not practically be very useful, I do wonder why it doesn't compile.
pub fn do_something(o: &(dyn Other + 'static)) {
}
trait Other {
fn do_something_other(&self);
}
impl<A> Other for dyn Fn(A) {
fn do_something_other(&self) {
do_something(self);
}
}
Here I implement a trait for a function type. This function type is generic over it's parameter. This means that if you were to do it like this:
pub fn do_something(o: &(dyn Other + 'static)) {
}
trait Other {
fn do_something_other(&self);
}
impl<F, A> Other for F where F: (Fn(A)) + 'static {
fn do_something_other(&self) {
do_something(self);
}
}
you get an error stating a type parameter is unconstrained.
I get this and don't believe it's possible to do it with generics. But the dynamic approach, why doesn't it work? It gives the following error:
I don't understand this error. It states I pass a Fn(A) -> (), which doesn't implement Other. However, this error occurs literally in the implementation of Other. How can it not be implemented here?
My first thought was because each closure is its own type. If it has to do with this, I find the error very weird.
The first construction fails because you cannot convert a &dyn A into a &dyn B, even when implementing B for dyn A.
trait A {}
trait B {
fn do_thing(&self);
}
impl B for dyn A {
fn do_thing(&self) {
let b: &dyn B = self;
}
}
error[E0308]: mismatched types
--> src/lib.rs:9:25
|
9 | let b: &dyn B = self;
| ------ ^^^^ expected trait `B`, found trait `A`
| |
| expected due to this
|
= note: expected reference `&dyn B`
found reference `&(dyn A + 'static)`
Well, you can convert traits but only with help from the source trait. But since in this case the source is Fn, that's not a route.
The second construction fails because Rust won't let you implement traits that can conflict. Trying to implement B for a type that implements A<_> will automatically be rejected because types can have multiple implementations of A<_>.
trait A<T> {}
trait B {
fn do_thing(&self);
}
impl<T, U> B for T where T: A<U> {
fn do_thing(&self) {}
}
error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
--> src/lib.rs:7:9
|
7 | impl<T, U> B for T where T: A<U> {
| ^ unconstrained type parameter
Regarding Fns in particular, its somewhat hard to tell since usually function objects only implement a single Fn trait. However, the keyword is usually since you can enable a feature on nightly to do just that. And the trait system usually doesn't play favorites.
So what can you do? Well the first method is still functional, just you have to keep the implementation within the trait. You can use the second method if you use a concrete types for the function arguments.
You can conceivably implement Other for &dyn Fn(_) (implementing it on the reference and not the object itself). But that's not particularly convenient with how Fn objects are usually used.
pub fn do_something(o: &dyn Other) {}
trait Other {
fn do_something_other(&self);
}
impl<A> Other for &dyn Fn(A) {
fn do_something_other(&self) {
do_something(self);
}
}
fn main() {
// THIS WORKS
let closure: &dyn Fn(_) = &|x: i32| println!("x: {}", x);
closure.do_something_other();
// THIS DOESN'T WORK
// let closure = |x: i32| println!("x: {}", x);
// closure.do_something_other();
}
Another option would be to make the Other trait generic in order to constrain A, but that of course depends on how its designed to be used.

No method found when extending the Iterator trait in Rust

I am trying to extend the functionality of the Iterator trait.
My statistics/iter_statistics.rs:
mod iter_statistics {
pub trait IterStatistics: Iterator<Item = f64> {
fn foo(&mut self) -> f64 {
0.0
}
}
impl IterStatistics for Iterator<Item = f64> {}
}
And statistics/mod.rs:
pub use self::iter_statistics::*;
mod iter_statistics;
And finally in my test code I have
use statistics::IterStatistics;
fn main() {
let z: Vec<f64> = vec![0.0, 3.0, -2.0];
assert_eq!(z.into_iter().foo(), 0.0);
}
When I run the test, I get:
error: no method name `foo` found for type `std::vec::IntoIter<f64>` in the current scope
assert_eq!(z.into_iter().foo(), 0.0);
^~~
which is strange to me since the docs for IntoIter<T> say it implements Iterator<Item=T>.
The impl you have written will only apply to trait objects (e.g. &mut Iterator<Item=f64>), not for all types that implement Iterator<Item=f64>. You want to write a generic impl like this:
impl<T: Iterator<Item=f64>> IterStatistics for T {}
Your implementation is backward. When programming in Rust, you have to forget about OO-inheritance and reason in terms of capabilities.
What does trait D: B means in Rust?
This means that D can only be implemented for types that already implement B. It's not inheritance, it's a constraint.
When to use trait D: B then?
The main reason to use this constraint is when you wish to provide a default implementation of D methods that will require associated items (traits, constants, methods) from B.
In general, you do not want to add more constraints than strictly necessary, as your clients may wish to use this trait in ways you did not foresee.
The one exception is when creating a trait as a "bundle of constraints", so that you do not have type T: SomeTrait + SomeOtherTrait + Send for all the methods your are implementing. This "bundle of constraints" should be empty, then; it's not a functional trait after all, just an "alias".
So, how to extend Iterator?
First declare a new trait:
pub trait IterStatistics {
fn foo(&mut self) -> f64;
}
Then implement it for all types already implementing Iterator<Item = f64>:
impl<T> IterStatistics for T
where T: Iterator<Item = f64>
{
fn foo(&mut self) -> f64 {
0.0
}
}

Resources