CodeBlanks Logo Icon CodeBlanks

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>.

Practice 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.

Starter code

main.rs
fn main() {
    // buraya yaz
}

Sample solution

main.rs
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());
}

Expected output

9 9

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 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 Correct answer
  • Delete the trait
  • Use unsafe
  • Nothing

Explanation: A method marked this way can be called on concrete types but not through dyn; the trait stays dyn compatible.

2 Exclude from dyn

Question
fn kopya(&self) -> Self
where
    Self: ____;
Answer
fn kopya(&self) -> Self
where
    Self: Sized;

Explanation: where Self: Sized excludes the method from trait objects.

3 Method and dyn compatibility

Term Meaning
fn alan(&self) -> f64 Compatible
fn kopya(&self) -> Self Not compatible
fn f<T>(&self, x: T) Not compatible (generic)
.. where Self: Sized Excluded

All lessons in Advanced