liveBook · Manning

Trait object

As explained in Code Like a Pro in Rust

A trait object is a dynamically dispatched value representing some concrete type that implements a specified trait.

Use `dyn Trait` when code needs to hold a value through a trait rather than name its concrete type. A trait object supports dynamic dispatch: method calls use a vtable lookup. For example, `Box<dyn MyTrait>` stores a value that implements `MyTrait`. That runtime lookup is a trade-off to consider in a tight loop. section 11.1

Trait objects are useful when a trait method must return a future but the implementation’s future type cannot be named as an associated type. An async observer can return `Pin<Box<dyn Future<Output = Self::Output> + 'a + Send>>`. The box holds the trait object; pinning lets the future be polled by `.await`. A plain `Box<dyn Future<…>>` fails here because the boxed future is not necessarily `Unpin`. section 8.6

Listing 8.4 Implementing the async Observer trait
pub trait Observer: Send + Sync {                                    #1
    type Subject;
    type Output;
    fn observe<'a>(                                                  #2
        &'a self,                                                    #3
        subject: &'a Self::Subject,                                  #4
    ) -> Pin<Box<dyn Future<Output = Self::Output> + 'a + Send>>;    #5
}

The observer signature ties the returned future to the lifetimes of both borrowed inputs and requires the future to be `Send`. section 8.6

The same technique provides a simple error return type: `Result<(), Box<dyn std::error::Error + Send + Sync>>` lets `?` surface errors through a CLI. It works when the errors implement `std::error::Error`, but it is a deliberately simple choice. If error-specific handling, logging, or messages matter, define an error type and use `From` to convert errors instead. section 10.6 section 10.8

How Code Like a Pro in Rust covers it

How deep it goes
Works through boxed futures, pinning, lifetimes, and `Send`; identifies vtable lookup as the dynamic-dispatch cost.
Examples
Shows an async observer returning a boxed future and a CLI returning `Box<dyn std::error::Error + Send + Sync>`.
What you can do after
Apply trait objects to return pinned async futures or propagate CLI errors, while weighing dispatch and error-handling trade-offs.
How it connects
Connects trait objects to dynamic dispatch, vtables, `Future`, `Pin`, and error handling.

Also explained in

Compare how 4 books explain trait object →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Code Like a Pro in Rust. The section links point to the parts of the book it draws on.