#13　Trait in Rust

## Introduction

If you have programmed before, probably you have ever used or heard interface. But what is interface? Well, an interface is a description of the actions that an object can do. In Object Oriented Programming(OOP), an Interface is a description of all functions that an object must have in order to be an "X". In Java, we can write like this.

```java
interface Drawable{  
        void draw();  
}  

class Rectangle implements Drawable{  
        public void draw(){
                System.out.println("drawing rectangle");
        }  
}  

class Circle implements Drawable{  
        public void draw(){
                System.out.println("drawing circle");
        }  
}  

class TestInterface1{  
public static void main(String args[]){  
        //In real scenario, object is provided by method e.g. getDrawable() 
        Drawable d = new Circle();  
        d.draw();  
}}
```

As you can see, there is one interface called Drawable and two classes: Rectangle, Circle. Drawable interface has one method which is draw(), then as a result of implementing Drawable interface, each class can have draw method and being able to implement specific function like printing "drawing rectangles" for Rectangle class, printing "drawing circle" for Circle class.  Other OOP language can write an interface like the above. But how about Rust? Is there any similar way? Yes, Rust does have a concept of interface is called "Trait". In this blog, I will explain what is Trait and how to use it. 


## What are traits in Rust?
A **trait** in Rust is a group of methods that are defined for particular type, then allow us to share behavior across their types and facilitates code reuse. They also enable us to write functions that accept different types for their arguments, as long as the type implements the required behavior in the form of trait.  
Let's see an example from Rust [standard io library](https://doc.rust-lang.org/std/io/trait.Write.html). 

```rust
pub trait Write {
    // Required methods
    fn write(&mut self, buf: &[u8]) -> Result<usize>;
    fn flush(&mut self) -> Result<()>;

    // Provided methods
    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result<usize> { ... }
    fn is_write_vectored(&self) -> bool { ... }
    fn write_all(&mut self, buf: &[u8]) -> Result<()> { ... }
    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> Result<()> { ... }
    fn write_fmt(&mut self, fmt: Arguments<'_>) -> Result<()> { ... }
    fn by_ref(&mut self) -> &mut Self
       where Self: Sized { ... }
}
```

Write trait is one of popular trait in Rust. As you can see, to define a trait, we use the **trait** keyword instead of **interface**. There are many methods in Write trait. Each function plays an important role to write bytes array. A struct that have to control bytes array like [File](https://doc.rust-lang.org/std/fs/struct.File.html), [TcpStream](https://doc.rust-lang.org/std/net/struct.TcpStream.html) implement this write trait. 

Another example from [here](https://doc.rust-lang.org/std/string/trait.ToString.html)

```rust
pub trait ToString {
    // Required method
    fn to_string(&self) -> String;
}

```

This "to_string" function is very useful when you want to convert to String type. For examle, you have a Person object or struct.

```rust
struct Person {
    name: String,
    age: u32,
}
```

when you want to print out this person's information, you can write like this

``` rust
fn main () {
    let person = Person { name: "Tom".to_string(), age: 32, };
    println!("{} is a {} year old", person.name, person.age);
}
```

This is one way to print out this person's information. However, you can also write like this

``` rust
impl ToString for Person {
  fn to_string(&self) -> String{
    return format!("{} is a {} year old", self.name, self.age);
  }
}

fn main() {
  let person = Person{name: "Tom".to_string(), age: 32,};
  println!("{}", person.to_string());
}
```

*[fomat!()](https://doc.rust-lang.org/std/macro.format.html) is a macro that create a String using interpolation of runtime expression.  

This is very useful when you have multiple person. If you implement ToString trait for person, you can call to_string() method from each person.

## Implementing a trait in Rust
In previous section, I touched a bit of implementing a trait, but to be more specific, to implement a trait, you have to declare an **impl** block for the type you want to implement the trait for. The syntax is like this. 

```rust
impl <trait> for <type> {}
```

Similar to implementing regular methods, you can write trait name after impl keyword. After trait name, use the for keyword in addition to name of the type you want to implement the trait for. You will need to implement all the methods that don't have default implementations. 

``` rust
trait WithName {
    fn new(name: String) -> Self;

    fn get_name(&self) -> &str;

    fn print(&self) {
            println!("My name is {}", self.get_name())
    }
}

struct Name(String);

impl WithName for Name {
    fn new(name: String) -> Self {
            Name(name)
    }

    fn get_name(&self) -> &str {
            &self.0
    }
}
```

## How to use traits in Rust
### Traits as Parameters
You can use trait as function parameters to allow the function to accept any type that can do **x**, where **x** is some behavior defined by a trait. You can also use trait bounds to refine and restrict generics, like accept any type T that implements a specified trait.  
Let's see an example.

``` rust
use std::io::Write;

fn say_hello(out: &mut dyn Write) -> std::io::Result<()> {
    out.write_all(b"hello world\n")?;
    out.flush();
}
```

say_hello method take one parameter that type is &mut dyn Write. It means "parameter will take mutable reference that implement Write trait".  After declaring say_hello method, you can use like 

``` rust
use std::fs::File;

let mut local_file = File::create("hello.txt")?;
say_hello(&mut local_file)?; // ok

let mut bytes = vec![];
say_hello(&mut bytes)?; // ok
```

First of all, you create hello.txt file, then pass to say_hello method. It is acceptable because File struct already implemented a Write trait, as I mentioned in previous chapter. 

In addition, you can also write like this as a generic function

``` rust
fn say_hello<W: Write>(out: &mut W) -> std::io::Result<()> {
    out.write_all(b"hello world\n");
    out.flush();
}
```

Pay attention to parameter, I used W instead of dyn Write. The generic type W specified as the type of the out parameters constrains the function such that the concrete type of the value passed as na argument for out must be the same. 

You can also specify more than one trait bound. This is what's known as a trait combo. To do this, you add the traits together: 
W: Trait1 + Trait2 + Trait3 ....

``` rust
 fn say_hello<W: Write + Debug>(out: &mut W) -> std::io::Result<()> {
    out.write_all(b"hello world\n");
    out.flush();
 }
```


### Returning Types that implement Traits
You can use traits as return types from functions. 

``` rust
use std::fmt::Debug;

fn impl_trait(n: u8) -> impl Debug {
    todo!()
}
```

By using impl Debug for the return type, you specify that the impl_trait function returns some type that implements the Debug trait without naming the concrete type. 


## Conclusion
I explored the difference between other programming language like Java and Rust, the concept of trait, how to define and how to implement trait, and how to use it. Hopefully, you have learned something new. However, this is just introduction of trait in Rust, unfortunately. I will explain about trait object in next blog. Thank you for reading. See you in next blog. 

## References
- https://doc.rust-lang.org/book/ch10-02-traits.html