I'm trying to implement a trait that has a supertrait, like so:
trait A {
fn do_a(&self);
}
trait B: A {
fn do_b(&self);
}
struct S {}
impl B for S {
fn do_a(&self) {}
fn do_b(&self) {}
}
When I run cargo build I get these compiler errors:
error[E0407]: method `do_a` is not a member of trait `B`
--> src/example.rs:12:5
|
12 | fn do_a(&self) {}
| ^^^^^^^^^^^^^^^^^ not a member of trait `B`
error[E0277]: the trait bound `example::S: example::A` is not satisfied
--> src/example.rs:11:6
|
5 | trait B: A {
| - required by this bound in `example::B`
...
11 | impl B for S {
| ^ the trait `example::A` is not implemented for `example::S`
I keep re-reading about supertraits, but I'm having trouble understanding this error.
The first error seems to contradict what trait B: A is telling the program to do.
The second error seems to contradict that the implementation of do_a(&self) {} satisfies A.
What am I missing here? Is my mental model wrong, or is my code missing some necessary boilerplate, or both?
I believe that the syntax is more about bounding the type (e.g. a type T that implements B must necessarily implement A) than inheritance in the object-oriented sense. If you write out the impls separately it compiles fine:
trait A {
fn do_a(&self);
}
trait B: A {
fn do_b(&self);
}
struct S {}
impl A for S {
fn do_a(&self) {}
}
impl B for S {
fn do_b(&self) {}
}
Playground
N.B. that if you remove the impl for A the code no longer compiles, the constraint that an impl of B must also impl A is no longer satisfied.
Related
I have the following Rust code
use std::{
cell::{Ref, RefCell},
rc::Rc,
};
trait TraitA {
fn data(&self) -> Ref<Vec<Rc<dyn TraitB>>>;
}
struct A {
data: RefCell<Vec<Rc<B>>>,
}
impl TraitA for A {
fn data(&self) -> Ref<Vec<Rc<dyn TraitB>>> {
self.data.borrow()
}
}
trait TraitB {}
struct B {}
impl TraitB for B {}
However I get the following error
error[E0308]: mismatched types
--> src/lib.rs:16:9
|
15 | fn data(&self) -> Ref<Vec<Rc<dyn TraitB>>> {
| ------------------------ expected `Ref<'_, Vec<Rc<(dyn TraitB + 'static)>>>` because of return type
16 | self.data.borrow()
| ^^^^^^^^^^^^^^^^^^ expected trait object `dyn TraitB`, found struct `B`
|
= note: expected struct `Ref<'_, Vec<Rc<(dyn TraitB + 'static)>>>`
found struct `Ref<'_, Vec<Rc<B>>>`
I have tried setting the data field in A to have type RefCell<Vec<Rc<dyn TraitB>>>. That will work.
However in my implementation I want to have the field contain the type B as I want the Vec to store only type B, not any implementation of TraitB.
My understanding is that Rust should be able to coerce the B type as required as long as it implements the trait TraitB, which in the example above, B does indeed implement TraitB.
For example, in the following snippet, Rc<dyn TraitB> is successfully coerced to Rc<B> no problem.
struct C {
weak_ref: Weak<B>,
}
impl C {
fn upgrade_weak_ref(&self) -> Rc<dyn TraitB> {
self.weak_ref.upgrade().unwrap()
}
}
So my question is, why is the coercion not working in the first example above. Is it because it's contained in a Ref? Is there a workaround or some way to make it work without changing the type of the data field in struct A?
Rc<dyn TraitB> is twice the size of Rc<B> (two usizes versus one). Therefore, there cannot be a way to coerce a Vec<Rc<B>> to Vec<Rc<dyn TraitB>> without rebuilding the vector.
You can store Vec<Rc<dyn TraitB>>, but have only methods that push Bs and therefore protect against misuse.
I have a trait Foo. This has a method which takes a generic type implementing Bar and is therefore not object safe:
trait Bar {}
trait Foo {
fn foofunc<B: Bar>(&self, b: B);
}
I want to make the trait Foo object safe. I gather the usual way to do this is to wrap it in a new, object-safe, trait (see here). Something along the lines of:
trait FooObjectSafe<B>
where B: Bar,
{
fn foofunc(&self, b: B);
}
impl<B, F> FooObjectSafe<B> for F
where B: Bar,
F: Foo,
{
fn foofunc(&self, b: B) {
Foo::foofunc(self, b)
}
}
This seems very limiting however. If there is a function use_foo which takes a generic type implementing Foo, then it cannot be used with FooObjectSafe without changing its signature (I don't want to do this as in practise these functions come from different modules and are very divorced from one another):
struct BarImpl;
impl Bar for BarImpl {}
struct FooImpl;
impl Foo for FooImpl {
fn foofunc<B: Bar>(&self, b: B) {}
}
fn main() {
let foos = [
Box::new(FooImpl{}) as Box<dyn FooObjectSafe<BarImpl>>,
Box::new(FooImpl{})
];
use_foo(foos[0]);
}
results in the error
error[E0277]: the trait bound `Box<dyn FooObjectSafe<BarImpl>>: Foo` is not satisfied
--> src/main.rs:43:13
|
43 | use_foo(foos[0]);
| ------- ^^^^^^^ the trait `Foo` is not implemented for `Box<dyn FooObjectSafe<BarImpl>>`
| |
| required by a bound introduced by this call
|
= help: the trait `Foo` is implemented for `FooImpl`
note: required by a bound in `use_foo`
--> src/main.rs:9:14
|
8 | fn use_foo<F>(foo: F)
| ------- required by a bound in this
9 | where F: Foo,
| ^^^ required by this bound in `use_foo`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` due to previous error
Is there a better way to do this? I suspect I'm making some architectural faux pas here, but what exactly?
Playground
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.
When working with a trait hierarchy, I got into the following problem: A trait (that is used as a trait object) should define a function that returns its own type. Of course, Self cannot be used since it would be different for each subtype. Instead, the trait should return the type of the trait object, like:
trait MySpecialTrait {
fn clone(&self) -> Box<dyn MySpecialTrait>;
}
So far, this works. But now I want to extract this functionality in its own generic supertrait to be able to write generic code that only relies on the supertrait properties, like this:
trait Cloneable<Output: ?Sized> {
fn clone(&self) -> Box<Output>;
}
trait MySpecialTrait: Cloneable<dyn MySpecialTrait> {
fn something(&self);
}
fn clone_all<T>(data: &Vec<Box<T>>) -> Vec<Box<T>>
where T: ?Sized + Cloneable<T>
{
data.iter().map(|x|x.clone()).collect()
}
But this code yields the following error:
error[E0391]: cycle detected when computing the supertraits of `MySpecialTrait`
--> src\main.rs:28:1
|
28 | trait MySpecialTrait: Cloneable<dyn MySpecialTrait> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: ...which again requires computing the supertraits of `MySpecialTrait`, completing the cycle
note: cycle used when collecting item types in top-level module
--> src\main.rs:28:1
|
28 | trait MySpecialTrait: Cloneable<dyn MySpecialTrait> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Using associated types like this does not change anything:
trait Cloneable {
type Output;
fn clone(&self) -> Box<Self::Output>;
}
trait MySpecialTrait: Cloneable<Output = dyn MySpecialTrait> {
fn something(&self);
}
Can someone explain to me why there is a cycle? I understand that in the general case of trait A: B the supertraits of B have to be known to calculate the supertraits of A, so
trait A: B {}
trait B: A {}
cannot work. But in this case, MySpecialTrait is only referenced in the generic type arguments, so why is it required to compute the supertraits of Cloneable<dyn MySpecialTrait>?
Apart from that, is there are workaround for this problem?
Edit
I do not want clone_all to work only with all concrete subtypes of Cloneable<T>, but also with all trait types, e.g. I want to call clone_all with an argument of type Vec<Box<dyn MySpecialTrait>>.
Suppose I want to create some type that wraps some other generic type, like so:
struct MyWrapper<T> {
pub inner: T,
}
Now I want my type to have a method if the inner type satisfies a specific bound. For example: I want to print it (in this example without using fmt traits for simplicity). To do this I have two possibilities: adding a bound to the impl or to the method itself.
Method Bound
impl<T> MyWrapper<T> {
pub fn print_inner(&self) where T: std::fmt::Display {
println!("[[ {} ]]", self.inner);
}
}
When calling this function with a MyWrapper<()> I get:
error[E0277]: `()` doesn't implement `std::fmt::Display`
--> src/main.rs:20:7
|
20 | w.print_inner();
| ^^^^^^^^^^^ `()` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string
|
= help: the trait `std::fmt::Display` is not implemented for `()`
Impl Bound
impl<T: std::fmt::Display> MyWrapper<T> {
pub fn print_inner(&self) {
println!("[[ {} ]]", self.inner);
}
}
Calling it incorrectly again, gives:
error[E0599]: no method named `print_inner` found for type `MyWrapper<()>` in the current scope
--> src/main.rs:19:7
|
1 | struct MyWrapper<T> {
| ------------------- method `print_inner` not found for this
...
19 | w.print_inner();
| ^^^^^^^^^^^
|
= note: the method `print_inner` exists but the following trait bounds were not satisfied:
`() : std::fmt::Display`
My question is: what is more idiomatic? Are there semantic differences (aside from lifetime stuff with traits, explained here)? Are there differences apart from the compiler message?
One semantic difference is that with the type bound on the method you can partially implement a trait:
trait Trait {
fn f(self) where Self: std::fmt::Display;
fn g(self);
}
struct Struct<T>(T);
impl<T> Trait for Struct<T> {
fn f(self) where Struct<T>: std::fmt::Display {
println!("{}", self);
}
fn g(self) {
println!("Hello world!");
}
}
fn main() {
let s = Struct(vec![1]);
// f is not implemented, but g is
//s.f();
s.g();
}
This may be useful if you have many optional methods with different type bounds, which would otherwise require separate traits.