Course contentsShow
← Rust
Lesson 1148 of 1,91010. Concurrency PrimitivesFree lesson

The Role of Arc in Type Erasure

You will use dynamic dispatch and reference counting to manage thread-safe polymorphic objects.

In this lesson, you will learn how to combine dynamic dispatch with Arc to share heterogeneous, thread-safe collections across multiple threads.

The Problem: When Types Don't Match

In Rust, generics (T) are typically resolved at compile-time (static dispatch). If you have a list of different objects that all implement the same trait—say, a collection of DatabaseWriter and LogWriter that both implement Writable—you cannot store them in a single Vec<T> because T must be one specific type.

To solve this, we use type erasure. By casting our concrete types into a trait object (e.g., Box<dyn Writable>), we "erase" the underlying type information, leaving only the knowledge that the object implements the trait.

Moving Erasure to Threads

While Box<dyn Trait> works for single-threaded ownership, it fails when you need to share that trait object across thread boundaries. Box implies unique ownership, meaning only one thread can own the erased object. This is where Arc (Atomic Reference Counting) becomes essential.

By using Arc<dyn Trait>, you create a thread-safe, shared pointer to the erased type. The Arc allows multiple threads to hold a reference to the same polymorphic object, while the dyn Trait allows those threads to call trait methods without knowing the concrete type of the object.

use std::sync::Arc;

trait Logger: Send + Sync {
    fn log(&self, msg: &str);
}

struct ConsoleLogger;
impl Logger for ConsoleLogger {
    fn log(&self, msg: &str) { println!("Console: {}", msg); }
}

fn main() {
    // Type erasure via Arc<dyn Logger>
    let logger: Arc<dyn Logger> = Arc::new(ConsoleLogger);

    let handle = std::thread::spawn(move || {
        logger.log("Hello from a background thread!");
    });

    handle.join().unwrap();
}

Why this works

For this pattern to be safe, the trait must include the Send and Sync marker traits. Because Arc provides atomic reference counting, it ensures that the erased object is only dropped once all threads are finished with it. This allows you to build sophisticated, decoupled architectures where threads can process varied tasks through a unified, shared interface.

Key Takeaway: Arc<dyn Trait> enables thread-safe type erasure, allowing you to share polymorphic objects across threads while maintaining memory safety through reference counting.