Extending Traits

Is it possible to extend traits?

I want to create a new trait which is extended from multiple base traits. Is this possible ?

Also, is it possible to implement multiple traits at once? Something like

impl A,B for X {
..
}
3 Likes

Rust has trait inheritance, it looks like this:

pub trait A {}
pub trait B: A {}

However, this does not mean that if a type extends B it will automatically extends A; trait inheritance is just a way to specify requirements, that is, trait B: A means that we can know that if some type T implements B, it also necessarily implements A.

Naturally, you can use this to specify that a trait extends a combination of other traits:

pub trait Something: Clone + Send + WhateverOtherTrait {}

Again, it just means that every type which implements Something must also implement Clone, Send and WhateverOtherTrait.

Implementing multiple traits at the same time is not possible. I think this is because in the vast majority of situations traits are sufficiently different so such implementation won't work anyway.

11 Likes

On the other hand, to specify that if a type extends A it will also automatically extend B you can use:

impl<T: A> B for T {}

in case you specified multiple types:

impl<T: Clone + Send + WhateverOtherTrait> Something for T {}

EDITED: previous version confused A: B with B: A

2 Likes

Because of this:

I found it's more convinenient to think about this feature as "type bounds" on trait implementor, than as a trait inheritance. Once you call it type bounds, it makes things more clear: you just declare you have to implement these traits for T in order to be able to implement the trait.

4 Likes

Imagine situation, when you need to implement two traits with the same method names, e.g. Display and Debug: both have method fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result. How can you distringuish different implementations of the method for these traits if you do it at the same time (impl Display + Debug for MyType {})?

1 Like

Isn't it the other way around? That is, if type T implements trait A, trait B is implemented as well.

1 Like

yea... no idea where my brain was while I was writing it...

1 Like

If two different traits have methods with the same name, you can use universal function call syntax (UFCS) to distinguish them:

http://doc.rust-lang.org/book/ufcs.html

1 Like

UFCS is about calling methods. I was talking about implementing methods, answering OP's answer.

1 Like

Oh, I missed that. Sorry!

A simple example based on the above discussion

trait OnOff{
    fn set_onoff(&self, b :bool){
       println!("OnOff Default");
    }
}

trait Brightness{
    fn set_brightness(&self, brightness: i32){
        println!("Brightness Default");
    }
}

//Now any type which implements 'Light' should implement 'OnOff' 
//& 'Brightness' as well 
trait Light: OnOff + Brightness{ }
      
struct MyLight{
    state: bool
}

//impl <MyLight: OnOff + Brightness>Light for MyLight{}
impl Light for MyLight{}

impl OnOff for MyLight{}
impl Brightness for MyLight{
    fn set_brightness(&self, brightness: i32){
        println!("Brightness = {}", brightness);
    }
}


fn main(){
    
    let my_light = MyLight{state: false};
    
    my_light.set_onoff(true);
    my_light.set_brightness(100);
}

Now what is the difference between these two

impl <MyLight: OnOff + Brightness>Light for MyLight{}

(vs)

impl Light for MyLight{}

Both are asking me to implement OnOff and Brightness

2 Likes
impl<MyLight: OnOff + Brightness> Light for MyLight {}

this one is 100% equal to

impl<T: OnOff + Brightness> Light for T {}

and implements the Light trait for all types that implement OnOff and Brightness. Even for types that someone created in another crate that uses your crate.

The other version

impl Light for MyLight {}

implements Light only for the MyLight struct

6 Likes

Good point. Thanks.

Working. Thanks :slight_smile: