# Advanced Traits There are more things that we have seen, more boilerplate and specifics. ## Specifying Placeholder Types in Trait Definitions with Associated Types They are syntactic sugar to make it easier to read, take the example: ```rust struct Container(i32, i32); // A trait which checks if 2 items are stored inside of container. // Also retrieves first or last value. trait Contains { fn contains(&self, _: &A, _: &B) -> bool; // Explicitly requires `A` and `B`. fn first(&self) -> i32; // Doesn't explicitly require `A` or `B`. fn last(&self) -> i32; // Doesn't explicitly require `A` or `B`. } impl Contains for Container { // True if the numbers stored are equal. fn contains(&self, number_1: &i32, number_2: &i32) -> bool { (&self.0 == number_1) && (&self.1 == number_2) } // Grab the first number. fn first(&self) -> i32 { self.0 } // Grab the last number. fn last(&self) -> i32 { self.1 } } // `C` contains `A` and `B`. In light of that, having to express `A` and // `B` again is a nuisance. fn difference(container: &C) -> i32 where C: Contains { container.last() - container.first() } fn main() { let number_1 = 3; let number_2 = 10; let container = Container(number_1, number_2); println!("Does container contain {} and {}: {}", &number_1, &number_2, container.contains(&number_1, &number_2)); println!("First number: {}", container.first()); println!("Last number: {}", container.last()); println!("The difference is: {}", difference(&container)); } ``` Using associated types, would be: ```rust struct Container(i32, i32); // A trait which checks if 2 items are stored inside of container. // Also retrieves first or last value. trait Contains { // Define generic types here which methods will be able to utilize. type A; // Same as a Generic, but without Generic usage type B; // Declaration assume types will be defined per implementation fn contains(&self, _: &Self::A, _: &Self::B) -> bool; fn first(&self) -> i32; fn last(&self) -> i32; } impl Contains for Container { // Specify what types `A` and `B` are. If the `input` type // is `Container(i32, i32)`, the `output` types are determined // as `i32` and `i32`. type A = i32; type B = i32; // We equate A/B to specific types, we can use the type to redefine // The functions or `&Self::A` and `&Self::B` which are valid here. fn contains(&self, number_1: &i32, number_2: &i32) -> bool { (&self.0 == number_1) && (&self.1 == number_2) } // Grab the first number. fn first(&self) -> i32 { self.0 } // Grab the last number. fn last(&self) -> i32 { self.1 } } // Now `Cointains` knows that the A/B types for Container are i32 // We don't have to use more Generics on the function! fn difference(container: &C) -> i32 { container.last() - container.first() } // Main does not change, the implementation was easier to write fn main() { let number_1 = 3; let number_2 = 10; let container = Container(number_1, number_2); println!("Does container contain {} and {}: {}", &number_1, &number_2, container.contains(&number_1, &number_2)); println!("First number: {}", container.first()); println!("Last number: {}", container.last()); println!("The difference is: {}", difference(&container)); } ``` ## Operator Overloading Overloading Operators is basically done by implementing traits, we can't use `+` as operator to overload but we can implement `Add` trait! ```rust use std::ops::Add; impl Add for Point { type Output = Point; fn add(self, other: Point) -> Output { Point { x: self.x + other.x, y: self.y + other.y, } } } ``` This can be done to the other traits in the `std::ops` module. ## Default Generic Type Parameters The `Add` trait, follows this implementation: ```rust trait Add { type Output; fn add(self, rhs: Rhs) -> Self::Output; } ``` If the implementor accepts that by default we will use `Self` type for the method, we will not need to change the Generic, it is already provided. But we coul also do: ```rust impl Add for Point { type Output = Point; fn add(self, other: Point3D) -> Output { Point { x:self.x + other.x, y: self.y + other.y, } } } ``` We have now implemented it for another type (like an Overload for the Add trait!). ## Fully Qualified Syntax for Disambiguation: Calling Methods with the Same Name Imagine 2 traits implement different functions but with the same `name` and `parameters`. To call the function as a method the compiler will not know which to call! ```rust trait Pilot { fn fly(&self); } trait Wizard { fn fly(&self); } struct Human; impl Pilot for Human { fn fly(&self) { println!("This is your captain speaking."); } } impl Wizard for Human { fn fly(&self) { println!("Up!"); } } impl Human { fn fly(&self) { println!("*waving arms furiously*"); } } fn main() { let person = Human; person.fly(); // Which one? -> The base one -> Human // What if Human did not implement fly() // Error! // We should do the extended call referring to // `trait::method(&variable)` Wizard::fly(&person); Pilot::fly(&person); } ``` What if the function does not implement `self` in any capacity? ```rust trait Animal { fn baby_name() -> String; } struct Dog; impl Dog { fn baby_name() -> String { String::from("Spot") } } impl Animal for Dog { fn baby_name() -> String { String::from("puppy") } } fn main() { println!("A baby dog is called a {}", Dog::baby_name()); // Calls the Dog only implementation Animal::baby_name(); // Error! What is it referring to? // Need the following syntax to express relationship // ::associated_function(); ::baby_name(); } ``` ## Using Supertraits to require One Trat's functionality within Another Trait You need 1 trait to use functionality from another trait. You require a trait being implemented! ```rust trait Trait: trait_required { // Trait that requires another to be implemented //... } struct Type {//...} // Generic Type impl Trait for Type {//...} // We want this Trait! impl trait_required for Type {//...} // Needed for Trait ``` ## Using the Newtype Pattern to implement external Traits on External Types In chapter 10, it was said we can't implement an External Trait on an External Type, one of them must be local! `newtype pattern` helps us circumvent that: - Create a new type in a tuple struct of 1 type - The type of the tuple will be the one we want to implement the type on - Then we wimplement the external trait on the tuple type! ```rust use std::fmt; struct Wrapper(Vec); // Wrapper is a tuple type over a Vec impl fmt::Display for Wrapper { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[{}]", self.0.join(", ")) } } fn main() { let w = Wrapper(vec![String::from("Hello"), String::from("world!")]); println!("w = {}", w); // Implictly use display for the Wrapper type, which in turn will do the job for the subtype Vec } ``` The issue here is that to actually use the `Vec` we can't access the data directly, we would need to implement the `Deref` Trait. Wait, can't we just do: `type.0.methods()` ? Yeah but it would be a bit annoying in the longrun and would not be quite readable.