0

I created an abstract data type for vectors in metric space but the compiler complains because it doesn't recognize that the implementation as an argument is of this type.

trait MetricPoint {
    fn square_distance(&self, other: &MetricPoint) -> f64;
}

struct RNPoint {
    coordinates: Vec<f64>,
}

impl RNPoint {
    fn new(coordinates: &[f64]) -> RNPoint {
        RNPoint {
            coordinates: coordinates.to_vec(),
        }
    }
}

impl MetricPoint for RNPoint {
    fn square_distance(self: &RNPoint, other: &RNPoint) -> f64 {
        let min_len = self.coordinates.len().min(other.coordinates.len());
        let mut sum = 0.0;
        for i in 0..min_len {
            let diff = self.coordinates[i] - other.coordinates[i];
            sum += diff * diff;
        }
        sum
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn square_distance() {
        let p1 = RNPoint::new(&[0.0, 0.0]);
        let p2 = RNPoint::new(&[1.0, 0.0]);
        let d = p1.square_distance(&p2);
        assert_eq!(d, 1.0)
    }
}

The compiler:

error[E0053]: method `square_distance` has an incompatible type for trait
  --> points/src/lib.rs:19:44
   |
2  |     fn square_distance(&self, other: &MetricPoint) -> f64;
   |                                      ------------ type in trait
...
19 |     fn square_distance(self:&RNPoint,other:&RNPoint)->f64 {
   |                                            ^^^^^^^^ expected trait MetricPoint, found struct `RNPoint`
   |
   = note: expected type `fn(&RNPoint, &dyn MetricPoint) -> f64`
              found type `fn(&RNPoint, &RNPoint) -> f64`

Why it doesn't recognize that an RNPoint is an MetricPoint?

gilcu2
  • 343
  • 3
  • 13
  • 3
    I you want the type of the implementor, use `Self` – Boiethios Jul 08 '19 at 09:46
  • 1
    BTW, you can use this answer to compute the sum: https://stackoverflow.com/questions/56930343/multiplying-elements-from-two-different-arrays : https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b19103b2509e041c72585561c9d3b0a1 – Boiethios Jul 08 '19 at 09:47
  • 2
    There is no such things as an *"abstract class"* in Rust. Please stick to the correct terminology. – hellow Jul 08 '19 at 09:48
  • You might change your title to "how to tell a trait function to take an argument implementing this trait" or something like that – Hugo Trentesaux Jul 08 '19 at 13:07

2 Answers2

2

You are not far from something that compiles and pass your test. Just change:

fn square_distance(&self, other: &MetricPoint) -> f64;

to

fn square_distance(&self, other: &Self) -> f64;

and optionnally

fn square_distance(self: &RNPoint, other: &RNPoint) -> f64

to

fn square_distance(self: &RNPoint, other: &Self) -> f64

By writing Self, you are specifying the type of the current structure. It's more generic and readable.

Hugo Trentesaux
  • 1,584
  • 1
  • 16
  • 30
  • 1
    Please explain why the changes are needed and where one can find some information about `Self` (e.g. https://stackoverflow.com/q/32304595) – hellow Jul 08 '19 at 13:33
0

Thanks. As some said but Hugo more clearly the solution is the self. Here is the final code:

trait Metric {
    fn distance(&self, other: &Self) -> f64;
}

struct RNPoint {
    coordinates: Vec<f64>,
}

impl RNPoint {
    fn new(coordinates: &[f64]) -> RNPoint {
        RNPoint {
            coordinates: coordinates.to_vec(),
        }
    }
}

impl Metric for RNPoint {

    fn distance(&self, other: &Self) -> f64 {
        let sum:f64=self.coordinates.iter()
            .zip(other.coordinates.iter())
            .map(|(&c1, &c2)| {
                let diff = c1 - c2;
                diff * diff
            })
            .sum();
         sum.sqrt()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_distance() {
        let p1 = RNPoint::new(&[0.0, 0.0]);
        let p2 = RNPoint::new(&[1.0, 0.0]);
        let d = p1.distance(&p2);
        assert_eq!(d, 1.0)
    }
}

About the abstract class I wrote Abstract Data Type but stack overflow changed it and I didn't notice. Sorry about

gilcu2
  • 343
  • 3
  • 13