Use Trait for diferent constraints for reference and owned ones

Hi, playing more, I found something interesting, we use traits we expect some properties and behavior, and some times we need a behavior when the element is owned, and others when is by reference, but the way trait Foo: Default would force to Default be implemented in both...., lets follow with an example:

trait FooTrait: Clone{};

struct Foo {
  val: f64
}

//This will works
impl FooTrait for Foo {}

// This will fails because we should not clone a &mut
impl FooTrait for &mut Foo{}

What I'm looking if we follow that example... is using one trait as constrain, only the Foo one to request have Clone, the ideal case would be &mut Foo to have the ToOwned Trait.

I can't found more info nor ways for this, I think any solution that in the end that uses impl FooTrait on the struct (and do not split in two traits) would be fine.

Because if we split the trait in a owned one and a reference one, we could not use the FooTrait as a constrain to use generics and would also duplicate all the code who depends on that.

Thx!

Generally this is a reason that you should avoid putting Default or Clone supertrait bounds on your traits; instead, code that uses the trait should specify FooTrait + Default when necessary and only when necessary. Another reason to avoid these sort of supertraits is that they make it impossible to use trait objects (dyn FooTrait).

trait FooTrait: Default (or adding fn new() -> Self; to the trait) is also unwisely restrictive because it means “all possible implementations of this trait can be constructed with no required inputs”. In most cases, you should let the caller of your generic code supply the instances, instead.

If you do have to use two traits, one strategy to avoid duplication is to make one trait a supertrait of the other:

trait Foo {
    // ... operations that can be implemented for any Foo reference ...
}
trait FooOwned: Foo + Clone {
    // ... additional operations that only make sense for owned values ...
}

Then you can write functions that are generic over T: Foo when possible and T: FooOwned when necessary, and values that implement FooOwned can also be used as Foo.

5 Likes

mmm, is hard in this way.... if Clone for example is used on the highest level of the library is not much issue, but if the function who uses Clone is on the base, then a lot of implementations above will need also it, this happens a lot rn to me... and on both, the owned values and the reference ones...... so even if is nice need a trait to run one.. I think is good have an alternative for this.