Course contentsShow
← Rust
Lesson 521 of 1,9105. Type System and TraitsFree lesson

Object Safety Rules

Design traits that allow for dynamic dispatch by strictly adhering to object safety criteria.

In this lesson, you will learn how to design traits so that they can be used as "trait objects" for dynamic dispatch without breaking Rust’s memory safety rules.

Why Object Safety Matters

When you use a trait as a type (like &dyn MyTrait), Rust needs to know exactly how to handle that type at runtime. Because a trait object is a Dynamically Sized Type (DST), the compiler needs a consistent way to look up the methods you are calling. Not every trait can be used this way. If a trait violates "object safety" rules, the compiler will stop you from turning it into a dyn object.

The Two Main Rules

A trait is object-safe only if it satisfies two critical requirements:

  1. No Generic Methods: You cannot have methods with their own generic type parameters. If a method is generic, the compiler would need to generate a unique version for every possible type you pass in. Since a dyn Trait hides the underlying concrete type, it wouldn't know which version of the method to call.
  2. No Self as a Return or Parameter: A method cannot return Self or take Self as an argument (other than the &self receiver). Because dyn Trait obscures the specific type that implements the trait, the compiler cannot know the size or identity of Self.

A Practical Example

Consider this trait that breaks the rules:

trait Processor {
    // Fails: Generic methods are not object-safe
    fn process<T>(&self, item: T);

    // Fails: Returning 'Self' is not object-safe
    fn clone_me(&self) -> Self;
}

If you tried to create a &dyn Processor, Rust wouldn't know how to size the return value of clone_me or how to specialize process for an unknown T. To fix this, you must refactor your interface to use concrete types or different abstractions (like Box<dyn Any> or returning a trait object instead of Self).

By keeping your trait methods monomorphic (non-generic) and avoiding references to Self in return positions, you ensure your design remains flexible enough to support dynamic dispatch.

Key Takeaway: A trait is object-safe if all its methods are non-generic and do not return or accept the Self type, allowing the compiler to generate a consistent "vtable" for dynamic dispatch.