Trait bounds for mathematical operations and self referential

I have some struct(s) that don't implement copy, e.g:

#[derive(Clone)]
struct My { val: f64 }

This struct implements all of the 4 mathematical crosses with itself, and in every case returns an owned My, i.e. Output = My.

impl Add<My> for My {...}; impl Add<My> for &My {...};
impl Add<&My> for My {...}; impl Add<&My> for &My {...};

I am trying to design a generic blanket trait such that I could define an operation like:

fn op<T: CrossAdd>(re: &T, owned: T) -> T {
    // contains all 4 crosses
    (re + ((re + re) + re)) + owned
}

But, I can't do it.

I have come close with help from @quinedot, who suggested the following:

trait ArithRef
  where
      Self: Sized,
      Self: Add<Self, Output = Self::Owned> + Add<Self::Owned, Output = Self::Owned>,
  {
      type Owned: Sized +
      Add<Self, Output = Self::Owned> + Add<Self::Owned, Output = Self::Owned>;
  }

  impl<T, Owned> ArithRef for T
  where
      T:    Add<T, Output = Owned> + Add<Owned, Output = Owned>,
      Owned: Add<T, Output = Owned> + Add<Owned, Output = Owned>,
  {
      type Owned = Owned;
  }

which allows one to write:

fn some_op<RefT: ArithRef>(re: RefT, re2: RefT) -> RefT::Owned
    {
        // clones are just clones of references
        (re.clone() + ((re.clone() + re.clone()) + re)) + re2
    }

I have another solution which avoids blanket implementation and directly adds traits to my types but that has other issues.

Am I trying to do something that fundamentally won't work? Or I just haven't discovered some appropriate solution yet?

if you add Copy as a supertait of ArithRef(all refs are Copy after all) you can reach

use std::ops::Add;
trait ArithRef : Copy
where
  Self: Sized,
  Self: Add<Self, Output = Self::Owned> + Add<Self::Owned, Output = Self::Owned>,
{
  type Owned: Sized +
  Add<Self, Output = Self::Owned> + Add<Self::Owned, Output = Self::Owned>;
}

impl<T, Owned> ArithRef for T
where
  T:Add<T, Output = Owned> + Add<Owned, Output = Owned> + Copy,
  Owned: Add<T, Output = Owned> + Add<Owned, Output = Owned>,
{
  type Owned = Owned;
}

fn op_inner<U : ArithRef>(re: U, owned: U::Owned) -> U::Owned
{
    // contains all 4 crosses
    (re + ((re + re) + re)) + owned
}


fn op<'a, T>(re: &'a T, owned: T) -> T 
where &'a T : ArithRef<Owned = T>
{
    op_inner(re, owned)
}

we would ideally want,

fn op<'a, T>(re: &'a T, owned: T) -> T 
where &'a T : ArithRef<Owned = T>
{
    (re + ((re + re) + re)) + owned
}

but we it doesn't work because of limitations in the compiler. there is an issue about it, bt it isn't clear that it will ever be fixed or is fixable

Thank you. (all refs are Copy after all) was a nice catch and this is certainly an improvement.

Using a trick to get general implied bounds, I came up with this:

trait CrossAdd
where
    Self: Sized 
        + Add<Self, Output = Self> 
        + for<'a> Add<&'a Self, Output = Self>
        + for<'a, 'b> ImpliedBound<
            &'a Self, 
            Is: Add<Self, Output = Self> + Add<&'b Self, Output = Self>,
        >,
{}

impl<T> CrossAdd for T
where
    T: Add<Self, Output = Self> + for<'a> Add<&'a Self, Output = Self>,
    for<'a, 'b> &'a T: Add<&'b T, Output = Self> + Add<Self, Output = Self>,
{}

Before that I tried a different approach and got to this, which doesn't require &Self (but did require Self: 'static in the implementation).

trait CrossAdd: Sized + Add<Self, Output = Self> + for<'a> Add<Self::Ref<'a>, Output = Self> {
    type Ref<'a>: Copy + Add<Self, Output = Self> + for<'b> Add<Self::Ref<'b>, Output = Self>;
}

Like the comments say, it stops working if you require Ref<'a> = &'a Self with a subtrait :sweat_smile:, perhaps due to the issue @Morgane55440 found. But maybe it's of interest to you anyway since it's more general along one axis.