# Implementing the Sum Trait

Is there a way to implement the `Sum` trait for non-std types? I’ve been searching for an answer and have yet to come across anything on how it might be done or if it is possible. I will start with the type I would like to sum, how I’ve implemented it now, and then how I would like to implement it to start.

I have this `Point` the type I would like to sum.

``````pub struct Point {
x: f64,
y: f64,
}
``````

And this is how I am currently summing it. The behaviour I would like is for the `x` and `y` from each `Point` to be added together.

``````pub fn sum_points(points: &[&Point]) -> Point {
Point {
x: points.iter().map(|point| point.x).sum(),
y: points.iter().map(|point| point.y).sum(),
}
}
``````

I would like to be able to write it like this.

``````pub fn sum_points(points: &[&Point]) -> Point {
points.iter().sum()
}
``````

But as I said I have not been able to find a way to do this yet. I have read enough to have been able to implement a subtraction.

``````use std::ops::Sub;

impl Sub for &Point {
type Output = Point;

fn sub(self, other: &Point) -> Point {
Point {
x: self.x - other.x,
y: self.y - other.y,
}
}
}
``````

But when I have tried to do similar things (copying from the Rust source code) I have not quite been able to get it to work.

``````std::iter::Sum;

impl Sum for Point {
fn sum(iter: Iterator<Item = Point>) -> Point {
iter.fold(Point { x: 0.0, y: 0.0 }, |a, b| Point {
x: a.x + b.x,
y: a.y + b.y,
})
}
}

impl<'a> Sum<&'a Point> for Point {
fn sum(iter: Iterator<Item = &'a Point>) -> Point {
iter.fold(Point { x: 0.0, y: 0.0 }, |a, b| Point {
x: a.x + b.x,
y: a.y + b.y,
})
}
}
``````

I am hoping someone can point me in the right direction to get this to work. Even if it is not currently possible it would be nice just to know why.

``````pub fn sum_points(points: &[&Point]) -> Point {
points.iter().sum()
}
``````

Thanks!

The way you’ve written this is using a trait as a value type, which you can’t do directly since trait objects are unsized. Your method needs to be generic just as `Sum` has declared it:

``````fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = A>
{
//...
}
``````

Thanks @cuviper, I’ll try that at some point today. From looking at what you wrote (which is similar to what is in the Rust docs) I’m still not sure what then the implementation would look like if you are still using generics. What then goes in `//...`?

Because without trying it this look quite right unless I am missing some kind of pattern matching magic?

``````fn sum<I>(iter: I) -> Self where I: Iterator<Item = A> {
iter.fold(Point { x: 0.0, y: 0.0 }, |a, b| Point {
x: a.x + b.x,
y: a.y + b.y,
})
}
``````

`A` is the generic type name used in the `std::iter::Sum` trait definition that represents the types you’re summing, but in your implementation of that trait you need to fill it in with a concrete type, e.g.:

``````impl<'a> Sum<&'a Self> for Point {
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = &'a Self>,
{
iter.fold(Self { x: 0.0, y: 0.0 }, |a, b| Self {
x: a.x + b.x,
y: a.y + b.y,
})
}
}
``````

You can replace all those `Self` instances with `Point` as well - `Self` is just a “shortcut” for the type you’re implementing the trait for (useful if, e.g., you rename the type, then don’t need to change these occurrences).

2 Likes

Sorry, I copied the signature directly from `Sum`, but I should have filled in `A``Point` and `&'a Point` respectively, or with `Self` is fine too. The generic part I was trying to highlight was the `I` in `fn sum<I>`.

The function body that you have looks fine. With `I: Iterator`, you can still fold it the same way.

1 Like

Thank you @vitalyd that did the trick. And no worries @cuviper it was a good start I just needed a little bit more help.

Even though I have got it going I’ll have to take a look at the Rust Book again. It has been a while since I have and I either missed, forgot, or they didn’t have the part on `Item` when I read it (quite likely I just forgot as I was brand new to Rust then).

In any case I really appreciate the help. Good work keeping the Rust community welcoming to ask questions like this. 