Simplify Generic Constraint Requirement

Hi all, again me )

I am wondering if the any proposal to simplify generics in such way ...

Rather than doing:

trait RunTimeReflection {
    fn get_num_fields() -> usize;
}

trait IPerson {
    fn get_first_name(&self) -> String;
    fn get_second_name(&self) -> String;
}

struct Person {
    first_name: String,
    second_name: String,
}

impl IPerson for Person {
    fn get_first_name(&self) -> String {
        self.first_name.clone()
    }

    fn get_second_name(&self) -> String {
        self.second_name.clone()
    }
}

impl RunTimeReflection for Person {
    fn get_num_fields() -> usize {
        2
    }
}

trait DebugPersonHolderReflection<T> where T: RunTimeReflection {
    fn print(t: &Vec<T>);
}

struct PersonHolder<T> where T: Sized + IPerson  {
    persons: Vec<T>,
}

impl<T> DebugPersonHolderReflection<T> for PersonHolder<T>
    where T: Sized + IPerson + RunTimeReflection {
    fn print(t: &Vec<T>) {
        for person in t {
            println!("num_fields: {}, first_name: {}, second_name: {}",
                     T::get_num_fields(), person.get_first_name(), person.get_second_name());
        }
    }
}

it would be nice if compiler takes by default constraints from interface and automatically:

trait RunTimeReflection {
    fn get_num_fields() -> usize;
}

trait IPerson {
    fn get_first_name(&self) -> String;
    fn get_second_name(&self) -> String;
}

struct Person {
    first_name: String,
    second_name: String,
}

impl IPerson for Person {
    fn get_first_name(&self) -> String {
        self.first_name.clone()
    }

    fn get_second_name(&self) -> String {
        self.second_name.clone()
    }
}

impl RunTimeReflection for Person {
    fn get_num_fields() -> usize {
        2
    }
}

trait DebugPersonHolderReflection<T> where T: RunTimeReflection {
    fn print(t: &Vec<T>);
}

struct PersonHolder<T> where T: Sized + IPerson  {
    persons: Vec<T>,
}

impl<T> DebugPersonHolderReflection<T> for PersonHolder<T> {
    // where T: Sized + IPerson + RunTimeReflection
    // (automatically get constraints from DebugPersonHolderReflection and PersonHolder)
    fn print(t: &Vec<T>) {
        for person in t {
            println!("num_fields: {}, first_name: {}, second_name: {}",
                     T::get_num_fields(), person.get_first_name(), person.get_second_name());
        }
    }
}

It would be nice if the same works for trait generic method

We violate DRY principle due to this ...

This is already accepted but not yet implemented in RFC 2089: Implied bounds.

3 Likes

I do not see in this proposal the following simplification:

trait MyTrait {
    fn message<T>(t: T) where T: RunTimeReflection;
}

impl MyTrait for Person {
    fn message<T>(t: T) where T: RunTimeReflection {
        unimplemented!()
    }
}

to:

trait MyTrait {
    fn message<T>(t: T) where T: RunTimeReflection;
}

impl MyTrait for Person {
    fn message<T>(t: T) {
        // (automatically get constraints from MyTrait) where T: RunTimeReflection
        unimplemented!()
    }
}

Will it work for method also ?