diff --git a/src/types/trait-object.md b/src/types/trait-object.md
index 3526b7add..c310adeb8 100644
--- a/src/types/trait-object.md
+++ b/src/types/trait-object.md
@@ -7,89 +7,241 @@
> _TraitObjectTypeOneBound_ :\
> `dyn`? [_TraitBound_]
-A *trait object* is an opaque value of another type that implements a set of
-traits. The set of traits is made up of an [object safe] *base trait* plus any
-number of [auto traits].
-
-Trait objects implement the base trait, its auto traits, and any [supertraits]
-of the base trait.
-
-Trait objects are written as the keyword `dyn` followed by a set of trait
-bounds, but with the following restrictions on the trait bounds. All traits
-except the first trait must be auto traits, there may not be more than one
-lifetime, and opt-out bounds (e.g. `?Sized`) are not allowed. Furthermore,
-paths to traits may be parenthesized.
-
-For example, given a trait `Trait`, the following are all trait objects:
-
-* `dyn Trait`
-* `dyn Trait + Send`
-* `dyn Trait + Send + Sync`
-* `dyn Trait + 'static`
-* `dyn Trait + Send + 'static`
-* `dyn Trait +`
-* `dyn 'static + Trait`.
-* `dyn (Trait)`
-
-> **Edition Differences**: Before the 2021 edition, the `dyn` keyword may be
-> omitted.
->
-> Note: For clarity, it is recommended to always use the `dyn` keyword on your
-> trait objects unless your codebase supports compiling with Rust 1.26 or lower.
-
-> **Edition Differences**: In the 2015 edition, if the first bound of the
-> trait object is a path that starts with `::`, then the `dyn` will be treated
-> as a part of the path. The first path can be put in parenthesis to get
-> around this. As such, if you want a trait object with the trait
-> `::your_module::Trait`, you should write it as `dyn (::your_module::Trait)`.
->
-> Beginning in the 2018 edition, `dyn` is a true keyword and is not allowed in
-> paths, so the parentheses are not necessary.
+A *trait object* is a powerful concept allowing you to work with values of
+different types as long as they implement a specified set of traits. This set
+consists of a primary, [object safe] *base trait*, and it can be extended with
+any number of [auto traits].
+
+A trait object represents a value of one type that adheres to the traits
+specified in its definition. It not only implements the base trait but also
+encompasses any associated [auto traits] and [supertraits] of the base trait.
+
+## Syntax and Examples
+
+The syntax for trait objects is concise:
+
+```rust
+dyn? TypeParamBounds
+```
+
+Here, `dyn` is the keyword, and `TypeParamBounds` represents the set of traits
+the object implements. While expressing trait bounds, some rules apply: only the
+first trait can be non-auto, there should be at most one lifetime, and opt-out
+bounds like `?Sized` are not allowed. Parentheses can be used to specify paths
+to traits.
+
+For example, given a trait `Trait`, here are some trait objects:
-Two trait object types alias each other if the base traits alias each other and
-if the sets of auto traits are the same and the lifetime bounds are the same.
-For example, `dyn Trait + Send + UnwindSafe` is the same as
-`dyn Trait + UnwindSafe + Send`.
+- `dyn Trait`
+- `dyn Trait + Send`
+- `dyn Trait + Send + Sync`
+- `dyn Trait + 'static`
+- `dyn Trait + Send + 'static`
+- `dyn Trait +`
+- `dyn 'static + Trait`
+- `dyn (Trait)`
-Due to the opaqueness of which concrete type the value is of, trait objects are
-[dynamically sized types]. Like all
-DSTs, trait objects are used
-behind some type of pointer; for example `&dyn SomeTrait` or
-`Box`. Each instance of a pointer to a trait object includes:
+> **Edition Differences**: Before the 2021 edition, `dyn` could be omitted. However,
+> for clarity, it is recommended to always use `dyn` unless your codebase supports
+> Rust 1.26 or lower.
- - a pointer to an instance of a type `T` that implements `SomeTrait`
- - a _virtual method table_, often just called a _vtable_, which contains, for
- each method of `SomeTrait` and its [supertraits] that `T` implements, a
- pointer to `T`'s implementation (i.e. a function pointer).
+> In the 2015 edition, if the first bound of the trait object is a path starting
+> with `::`, then the `dyn` is considered part of the path. In such cases, use
+> parentheses to avoid issues.
-The purpose of trait objects is to permit "late binding" of methods. Calling a
-method on a trait object results in virtual dispatch at runtime: that is, a
-function pointer is loaded from the trait object vtable and invoked indirectly.
-The actual implementation for each vtable entry can vary on an object-by-object
-basis.
+> Starting from the 2018 edition, `dyn` is a true keyword, and parentheses are not
+> necessary.
-An example of a trait object:
+Two trait object types are considered identical if their base traits match, auto
+traits are the same, and the lifetime bounds are identical. For instance,
+`dyn Trait + Send + UnwindSafe` is equivalent to `dyn Trait + UnwindSafe + Send`.
+
+## Trait Objects in Action
+
+Due to the opaque nature of trait objects, they are considered
+[dynamically sized types (DSTs)]. They are typically used with pointers like
+`&dyn SomeTrait` or `Box`. A pointer to a trait object includes a
+pointer to an instance of the implementing type and a _virtual method table_
+(vtable)containing function pointers for each method the type implements.
+
+The primary purpose of trait objects is to enable "late binding" of methods.
+Invoking a method on a trait object results in virtual dispatch at runtime.
+The correct function implementation is determined by loading a function pointer
+from the trait object's vtable.
+
+## Example Code
+
+Let's consider some examples about trait objects:
+
+### 1. **Trait Object with Multiple Traits**
```rust
-trait Printable {
- fn stringify(&self) -> String;
+trait Shape {
+ fn area(&self) -> f64;
+}
+
+trait Drawable {
+ fn draw(&self);
+}
+
+trait ShapeAndDrawable: Shape + Drawable {}
+
+struct Circle {
+ radius: f64,
}
-impl Printable for i32 {
- fn stringify(&self) -> String { self.to_string() }
+impl Shape for Circle {
+ fn area(&self) -> f64 {
+ std::f64::consts::PI * self.radius * self.radius
+ }
}
-fn print(a: Box) {
- println!("{}", a.stringify());
+impl Drawable for Circle {
+ fn draw(&self) {
+ println!("Drawing a circle");
+ }
+}
+
+impl ShapeAndDrawable for Circle {}
+
+fn process_shapes(shapes: Vec>) {
+ for shape in shapes {
+ println!("Area: {:.2}", shape.area());
+ shape.draw();
+ }
}
fn main() {
- print(Box::new(10) as Box);
+ let circle = Circle { radius: 3.0 };
+
+ let circle_trait_object: Box = Box::new(circle);
+
+ process_shapes(vec![circle_trait_object]);
}
+
+// Output
+
+// Area: 28.27
+// Drawing a circle
```
-In this example, the trait `Printable` occurs as a trait object in both the
-type signature of `print`, and the cast expression in `main`.
+This example defines two traits, `Shape` and `Drawable`, representing geometric shapes
+and drawable objects. The `Circle` struct implements both traits. The `process_shapes`
+function accepts a vector of trait objects that combine `Shape` and `Drawable`. In `main`,
+we create a `Circle` instance, convert it to a trait object, and process it using the
+generic function.
+
+### 2. **Dynamic Dispatch with Generics**
+
+```rust
+trait Processor {
+ fn process(&self, data: T);
+}
+
+struct StringProcessor;
+
+impl Processor<&str> for StringProcessor {
+ fn process(&self, data: &str) {
+ println!("Processing string: {}", data);
+ }
+}
+
+fn process_data(processor: Box>, data: T) {
+ processor.process(data);
+}
+
+fn main() {
+ let string_processor = StringProcessor;
+
+ let dynamic_processor: Box> = Box::new(string_processor);
+
+ process_data(dynamic_processor, "Hello, Trait Objects!");
+}
+
+// Output
+
+// Processing string: Hello, Trait Objects!
+```
+
+This example demonstrates dynamic dispatch with generics. The `Processor` trait has a
+generic method, and we implement it for a specific type (`&str`). In `main`, we create
+a `StringProcessor` instance, convert it to a trait object with dynamic dispatch, and
+use it to process a string.
+
+### 3. **Trait Objects with Default Implementations**
+
+```rust
+trait Logger {
+ fn log(&self, message: &str) {
+ println!("Default Log: {}", message);
+ }
+}
+
+struct AppLogger;
+
+impl Logger for AppLogger {
+ fn log(&self, message: &str) {
+ println!("App Log: {}", message);
+ }
+}
+
+fn main() {
+ let app_logger = AppLogger;
+
+ let logger_trait_object: Box = Box::new(app_logger);
+
+ logger_trait_object.log("Custom Log Message");
+}
+
+// Output
+
+// App Log: Custom Log Message
+```
+
+In this example, the `Logger` trait has a default implementation for the `log` method.
+The `AppLogger` struct implements this trait, and in `main`, we create an instance,
+convert it to a trait object, and use the default implementation to log a custom message.
+
+### 4. **Trait Objects and Associated Types**
+
+```rust
+trait Transformer {
+ type Output;
+ fn transform(&self) -> Self::Output;
+}
+
+struct UppercaseString(String);
+
+impl Transformer for UppercaseString {
+ type Output = String;
+ fn transform(&self) -> Self::Output {
+ self.0.to_uppercase()
+ }
+}
+
+fn main() {
+ let uppercase_string = UppercaseString("hello".to_string());
+
+ let transformer_trait_object: Box> =
+ Box::new(uppercase_string);
+
+ let result = transformer_trait_object.transform();
+ println!("Transformed: {}", result);
+}
+
+// Output
+
+// Transformed: HELLO
+```
+
+This example introduces a trait with an associated type. The `Transformer` trait has a
+method `transform` with an associated type `Output`. The `UppercaseString` struct
+implements this trait, and in `main`, we create an instance, convert it to a trait
+object, and use it to transform a string.
+
+These examples cover a range of scenarios, from combining multiple traits to dealing
+with generics, default implementations, and associated types, showcasing the flexibility
+and power of trait objects in Rust.
## Trait Object Lifetime Bounds
@@ -102,6 +254,6 @@ inferred with a sensible choice.
[_TypeParamBounds_]: ../trait-bounds.md
[auto traits]: ../special-types-and-traits.md#auto-traits
[defaults]: ../lifetime-elision.md#default-trait-object-lifetimes
-[dynamically sized types]: ../dynamically-sized-types.md
+[dynamically sized types (DSTs)]: ../dynamically-sized-types.md
[object safe]: ../items/traits.md#object-safety
[supertraits]: ../items/traits.md#supertraits