Struggling with Add Ops for Custom Struct

Hello!

Can anyone explain to me why this will not work inside of the function "dist"?

use std::ops::{Add, Sub};

#[derive(Debug, Copy, Clone, PartialEq)]
struct T3<T> {
  x: T,
  y: T,
  z: T
}

// Construct type for particle
struct Particle<T,U>{
  pos:  T3<T>,
  vel:  T3<T>,
  rhop: U 
}

// Notice that the implementation uses the associated type `Output`.
impl<T: Add<Output = T>> Add for T3<T> {
  type Output = Self;

  fn add(self, other: Self) -> Self::Output {
      Self {
          x: self.x + other.x,
          y: self.y + other.y,
          z: self.z + other.z
      }
  }
}

fn dist<T,U>(arg1: Particle<T,U>, arg2: Particle<T,U>){
  let a   = arg1.pos;
  let b   = arg2.pos;
  let res = a + b;
}

The last line "let res = a + b" will not work and I get the error:

image

I do not understand why this implementation would be missing when I have defined it? If I do it directly in main, i.e. without defining "dist" it works.

Kind regards

Add is only implemented when T implements Add (T: Add... bound on the impl). This requirement is not reflected in the function's signature, so there's no guarantee T, and therefore T3, implements Add when dist is called.

2 Likes

Thanks for the reply! What I did was to add as such:

image

Which made it work. Not completely sure why though - this is my first time trying to more generic programming in Rust. I don't really understand what "Add<Output = T>" means in "words".

Kind regards

T: Add<Output = T> is a trait bound that basically says "here, T should implement Add". The Output = T refers to Add's associated type. They can be a bit complex but here it just means that when you add two Ts, the output should be of type T as well.

You've implement Add for Particle with
impl<T: Add<Output = T>> Add for T3<T> { ... }
which makes sense. In the implementation you add Ts together to make more Ts, so we need this trait bound to make sure we can do that with T. But the bound also means that Add is only implemented for T3 if Add is implemented for T.

Consider for example that we can make the following T3:

    let t3 = T3 {
        x: vec![1],
        y: vec![2],
        z: vec![3],
    };

In this case the Add implementation cannot be used because Add is not implemented for vectors. The trait bound on dist is required to make sure that the T3s inside the given Particles can be added together.

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.