Giving default implementation of trait based on other traits


#1

Hi,

For my project I am trying to create a newtypes like this -

pub struct Length (u64);
pub struct SeqNum (u32);
pub struct TagNum (u32);

pub struct Amt (f64);
pub struct Qty (f64);

I have defined traits for getter & setter -

pub trait FixType {
        type output;

        fn get_val(&self) -> Self::output;

        fn set_val<T>(&mut self, val: T); 
}

pub trait Setter<Other=Self> {
        fn set(&mut self, other: Other);
    }

pub trait Getter {
        type output;
        fn get(&self) -> Self::output;
    }

Sample implementation is as follow -

impl Getter for SeqNum {
        type output = u32;

        fn get(&self) -> u32 {
            self.0
        }
    }

    impl Setter for SeqNum {
        fn set(&mut self, other: Int) {
            self.0 = other.0;
        }
    }

    impl Setter<u16> for SeqNum {
        fn set(&mut self, other: u16) {
            self.0 = other as u32;
        }
    }

    impl Setter<u64> for SeqNum {
        fn set(&mut self, other: u64) {
            self.0 = other as u32;
        }
    }

I want to give default implement FixType trait for any types which implement Setter and Getter like below -

impl<I: Getter + Setter> FixType for I {
        type output = I::output; // I want to write something which say that the output of this return should be the output return by the Getter implementation. 

        fn get_val(&self) -> Self::output {
            self.get()
        }

        fn set_val<T>(&mut self, val: T ) {
            self.set(val);
        }
    }

I want to have FixType implementation because later I want to use hashmaps or Vec which are generic over any type which is FixType.

I get below error in set_val -

"mismatched types\n\nexpected type parameter, found a different type parameter\n\nnote: expected type I\nfound type T",

Also, not sure if my get_val and output parameters are correct. Could someone please in understanding how to model this better?

Regards,
Gaurav


#2

You probably want something like this.

The set_val definition in your FixType:

pub trait FixType {
        type output;

        fn get_val(&self) -> Self::output;

        fn set_val<T>(&mut self, val: T); 
}

doesn’t really jive with the blanket impl that you wanted. This set_val says it can take any T whatsoever; there’s no way to satisfy that with a Setter because your I type parameter would need to implement Setter for every conceivable T. Semantically, it probably also doesn’t quite make sense to have a specific output type but any input type.

I changed the definition of set_val to what I think you really meant but let me know if that’s not true.

As an aside, associated type parameters are usually PascalCased, not lowercase, but I didn’t change it.


#3

Hi Vitaly,

Yeah this seems closer to what I want but I haven’t had time to tinker with the code. If I understand correctly, I need to implement Into trait for all types to convert primitive type to my type. Am I correct?

Regards,


#4

Yeah, the Into part is a bit of extra flexibility so callers can pass types that can be converted to the type FixType uses underneath. Depending on the output's actual type, you may already get some of these conversions for free (ie they’re in std).