Way to implement Generic Vector norm

Hello Rustaceans,

I'm still learning Generics through my Vector2D . To be honest, I didn't expect it to be that hard, but, the exploration is quite interesting to learn. I looked at the forum, and read some kind of similar topics.
I have implemented Add/Sub/Mul/Div operator, Defaut, PartialEq traits and now I'm trying to implement the norm() / length() operation. The difficulty here is that sqrt() only exist on f32 and f64 types. By looking at several libraries, I noticed that many of them provide the squared norm instead of the norm to avoid the problem with sqrt() on float types. This make me think that this is not a trivial problem :roll_eyes:

Here is a pseudo code (doesn't compile) to express my idea:


impl<T: Copy + std::ops::Mul<Output=T> + std::ops::Add<Output=T>> Vector2D<T> {
    // Compute euclidian norm (length) of self vector.
    fn norm(self: &Self) -> T {
        let tmp: T = (self.x * self.x) + (self.y * self.y);
        let tmp: f64 = tmp as f64;   // Here I need a magical cast to f64
        let tmp = tmp.sqrt();
        tmp as T    // Here I need a magical cast from f64 to T
    }
}

Rust compiler clearly indicates that 'as' can only be used for primitive types. I could not find solution for this.

Now, I'm thinking about creating a Sqrt trait with a method computing sqrt and adding this trait to the bound and then provide implementation of this trait for various primitive types.

impl<T: Copy + std::ops::Mul<Output=T> + std::ops::Add<Output=T> + SQRT> Vector2D<T> {
    // Compute euclidian norm (length) of self vector.
    fn norm(self: &Self) -> T ...

As you probably realize, I'm not confident with the feasibility of this. Being a beginner, I also have no idea about macros, and the possibilities they offer.

For completeness, I have to say that I already choose to remove generic for my Vector2D, and provide both f32 and f64 implementation. The idea of using Vector is nice from intellectual point of view, but useless for me even if a good exercise.

Nevertheless, I'm interested to know how a competent Rustacean would have solved this problem.

Kind regards

Yes, writing a trait that provides the square root is the way to go here if you want to be generic. You don't have to do it yourself, though: there's at least num::Float (which abstracts over f32 and f64) and num::Pow (which you could use to compute the square root). In general using the num crate is very much recommended when working with math generically due to the scarcity of relevant abstractions in std.

2 Likes

Thanks, for your reply.

I heard about these crates. If I write and experiment this code that's for learning purposes only. I don't plan to get something really useful. Coming from Java/C++ it's sometime difficult for me to avoid thinking with these language logic, and I'm trying to get experience by coding something that I know well and focus on Rust :wink:

At the end, I changed my mind. Instead of removing generic on my struct and providing f32 and f64 implementation, I kept generic and provide f32, f64 specialization for norm/normalize method. So there is no duplicated code. The drawback is that trying to compute norm on Vector2D will ends with a compiler error :

method not found in `vector::Vector2D<i64>`