struct Square {
l: f32,
}
pub trait Area {
fn area(&self) -> f32
where
Self: Shape;
}
impl Area for Square {
fn area(&self) -> f32 {
&self.l * &self.l
}
}
pub trait Shape
where
Self: Area,
{
}
impl Shape for Square {}
fn main() {
let _a: Vec<Box<dyn Shape>> = vec![];
}
warning: the trait `Shape` cannot be made into an object
Also warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
The above code compiles.
I don't understand why Shape is not allowed to be a trait object. It follows all the rules given here Traits - The Rust Reference
Don't have a practical application I was just playing around.
This is the full compiler error from the Playground:
warning: the trait `Shape` cannot be made into an object
--> src/main.rs:6:8
|
6 | fn area(&self) -> f32
| ^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #51443 <https://github.com/rust-lang/rust/issues/51443>
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>
--> src/main.rs:6:8
|
6 | fn area(&self) -> f32
| ^^^^ ...because method `area` references the `Self` type in its `where` clause
...
16 | pub trait Shape
| ----- this trait cannot be made into an object...
= help: consider moving `area` to another trait
= note: `#[warn(where_clauses_object_safety)]` on by default
You cannot reference Self
in trait definitions because it is not object safe. Trait objects (dyn Trait
) can only be used if the trait is object safe.
Try making Area
a supertrait of Shape
:
pub trait Area: Shape {
fn area(&self) -> f32;
}
And/or using a blanket impl for Shape
:
impl<T: Area> Shape for T {}
Here's an updated Playground.
2 Likes
I thought both of these pieces of code are same and meant anything implementing shape must also implement area.
What is the difference between them?
I don't understand why Self is not object safe. The code given below uses Self in trait definitions but does not give any warnings. I just removed where Self:Shape
for Area trait
struct Square {
l: f32,
}
pub trait Area {
fn area(&self) -> f32;
}
impl Area for Square {
fn area(&self) -> f32 {
&self.l * &self.l
}
}
pub trait Shape
where
Self: Area,
{
}
impl Shape for Square {}
fn main() {
let _a: Vec<Box<dyn Shape>> = vec![];
}
pub trait Area {
fn area(&self) -> f32
where
Self: Shape;
}
The above code means that anything can implement Area
, but the area()
method is only available for things implementing Shape
. Here's a playground example of something implementing Area
but not Shape
. Area
isn't considered object safe in this case because the check on whether a type implements Shape
can't be made dynamic. You could make it object safe by adding a Self : Sized
bound to the area()
method to make it unavailable for trait objects (but then you would have a trait object with no methods in this case).
pub trait Area: Shape {
fn area(&self) -> f32;
}
The above code means anything implementing Area
must implement Shape
. This can be seen in a modified version of my previous example, where it now errors on the attempt to implement Area
.
3 Likes