Rust
Object safety
Learn the object safety rules.
Object safety
For a trait to be used with dyn, it must be dyn compatible (formerly called object safe). Blocking cases: methods returning Self, methods taking generic type parameters, associated functions without self, and a Sized supertrait. Because these methods can't be called through a vtable without knowing the concrete type:
trait Kopyalanir {
fn kopya(&self) -> Self; // returns Self: not dyn compatible
}
// let x: Box<dyn Kopyalanir>; // E0038
That's why Clone can't be used as a trait object.
where Self: Sized
To keep using the rest of the trait with dyn, separate the problematic method:
trait Sekil {
fn alan(&self) -> f64;
fn kopya(&self) -> Self
where
Self: Sized;
}
let k = Kare(3.0);
let k2 = k.kopya(); // works on the concrete type
let d: Box<dyn Sekil> = Box::new(k2); // dyn is possible too
// d.kopya(); // can't be called through dyn
The common solution for a boxed copy is a separate method: fn kutulu_kopya(&self) -> Box<dyn Sekil>.
Exercise A compatible shape trait
Write the Sekil trait above and implement it for #[derive(Clone)] struct Kare(f64); (kopya = self.clone()). Print the area of Kare(3.0).kopya() and, after putting it in a Box<dyn Sekil>, its area through dyn, separated by a space.
Show example solution
trait Sekil {
fn alan(&self) -> f64;
fn kopya(&self) -> Self
where
Self: Sized;
}
#[derive(Clone)]
struct Kare(f64);
impl Sekil for Kare {
fn alan(&self) -> f64 {
self.0 * self.0
}
fn kopya(&self) -> Self {
self.clone()
}
}
fn main() {
let k2 = Kare(3.0).kopya();
let a = k2.alan();
let d: Box<dyn Sekil> = Box::new(k2);
println!("{} {}", a, d.alan());
}
Test yourself
-
If a trait has a single non-dyn-compatible method, what can be done?
- Add where Self: Sized to that method to exclude it from trait objects
- Delete the trait
- Use unsafe
- Nothing
Show answer
Add where Self: Sized to that method to exclude it from trait objects — A method marked this way can be called on concrete types but not through dyn; the trait stays dyn compatible.
-
Exclude from dyn
fn kopya(&self) -> Self
where
Self: ____;
Show answer
fn kopya(&self) -> Self
where
Self: Sized;
-
Method and dyn compatibility
- fn alan(&self) -> f64
- Compatible
- fn kopya(&self) -> Self
- Not compatible
- fn f<T>(&self, x: T)
- Not compatible (generic)
- .. where Self: Sized
- Excluded
Next lesson: &dyn Trait