musako
musako

Reputation: 1267

How do I implement abs function to custom type in Rust?

I am currently writing a numerical code using Rust. So I created a type for it myself. This trait is a data way to allow rust_ndarray to perform calculations on both f64 and f32. To make it multi-threaded, we added Sync and Send to the bounds of the trait. How can I implement a function in my own type that is found in other integer types?

use ndarray_linalg::lapack::Lapack;
use ndarray_linalg::types::Scalar;
use ndarray_linalg::rand_distr::Float;
use std::marker::{Sync, Send};

pub trait Type: Lapack + Scalar + Float + Sync + Send {}

impl Type for f32 {}
impl Type for f64 {}

I would like to write my own function to find the absolute value for this Type. How can I implement it? I did the implementation as shown below and got the following error.

impl Type {
    pub fn abs(&self) -> Self {
        if self.0 > 0. {self.0}
        else {-1. * self.0}
    }
}

I received the following error. Given the errors I've received, it seems like there is a problem with the trait boundary I'm using in Type. I also tried including ParticalOrd and ParticalEq in the trate boundary and received the same error.

note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
    |
   ::: src/traits.rs:7:11
    |
7   | pub trait Type: Lapack + Scalar + Float + Sync + Send {}
    |           ------- this trait cannot be made into an object...
   --> /Users/~~/.cargo/registry/src/github.com-1ecc6299db9ec823/rand_distr-0.2.2/src/utils.rs:24:33
    |
24  | pub trait Float: Copy + Sized + cmp::PartialOrd
    |                                 ^^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter
25  |     + ops::Neg<Output = Self>
26  |     + ops::Add<Output = Self>
    |       ^^^^^^^^^^^^^^^^^^^^^^^
    |       |        |
    |       |        ...because it uses `Self` as a type parameter
    |       ...because it uses `Self` as a type parameter
27  |     + ops::Sub<Output = Self>
    |       ^^^^^^^^^^^^^^^^^^^^^^^
    |       |        |
    |       |        ...because it uses `Self` as a type parameter
    |       ...because it uses `Self` as a type parameter
28  |     + ops::Mul<Output = Self>
    |       ^^^^^^^^^^^^^^^^^^^^^^^
    |       |        |
    |       |        ...because it uses `Self` as a type parameter
    |       ...because it uses `Self` as a type parameter
29  |     + ops::Div<Output = Self>
    |       ^^^^^^^^^^^^^^^^^^^^^^^
    |       |        |
    |       |        ...because it uses `Self` as a type parameter
    |       ...because it uses `Self` as a type parameter
30  |     + ops::AddAssign + ops::SubAssign + ops::MulAssign + ops::DivAssign
    |       ^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter
    |       |                |                |
    |       |                |                ...because it uses `Self` as a type parameter
    |       |                ...because it uses `Self` as a type parameter
    |       ...because it uses `Self` as a type parameter
    |
   ::: /Users/~~/.cargo/registry/src/github.com-1ecc6299db9ec823/cauchy-0.2.2/src/lib.rs:44:7
    |
44  |     + Sum
    |       ^^^ ...because it uses `Self` as a type parameter
45  |     + Product
    |       ^^^^^^^ ...because it uses `Self` as a type parameter
    |
   ::: /Users/~~/.cargo/registry/src/github.com-1ecc6299db9ec823/num-traits-0.2.14/src/lib.rs:67:41
    |
67  | pub trait Num: PartialEq + Zero + One + NumOps {
    |                ^^^^^^^^^                ^^^^^^ ...because it uses `Self` as a type parameter
    |                |
    |                ...because it uses `Self` as a type parameter
...
149 | pub trait NumAssign: Num + NumAssignOps {}
    |                            ^^^^^^^^^^^^ ...because it uses `Self` as a type parameter
    |
   ::: /Users/~~/.cargo/registry/src/github.com-1ecc6299db9ec823/num-traits-0.2.14/src/identities.rs:12:25
    |
12  | pub trait Zero: Sized + Add<Self, Output = Self> {
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^
    |                         |         |
    |                         |         ...because it uses `Self` as a type parameter
    |                         ...because it uses `Self` as a type parameter
...
90  | pub trait One: Sized + Mul<Self, Output = Self> {
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^
    |                        |         |
    |                        |         ...because it uses `Self` as a type parameter
    |                        ...because it uses `Self` as a type parameter

error[E0038]: the trait `Type` cannot be made into an object
   --> src/traits.rs:13:6



13  | impl Type {
    |      ^^^^^^^ `Type` cannot be made into an object
    |
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
    |
   ::: src/traits.rs:7:11
    |
7   | pub trait Type: Lapack + Scalar + Float + Sync + Send {}
    |           ------- this trait cannot be made into an object...
   --> /Users/~~/.cargo/registry/src/github.com-1ecc6299db9ec823/rand_distr-0.2.2/src/utils.rs:24:33
    |
24  | pub trait Float: Copy + Sized + cmp::PartialOrd
    |                                 ^^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter
25  |     + ops::Neg<Output = Self>
26  |     + ops::Add<Output = Self>
    |       ^^^^^^^^^^^^^^^^^^^^^^^
    |       |        |
    |       |        ...because it uses `Self` as a type parameter
    |       ...because it uses `Self` as a type parameter
27  |     + ops::Sub<Output = Self>
    |       ^^^^^^^^^^^^^^^^^^^^^^^
    |       |        |
    |       |        ...because it uses `Self` as a type parameter
    |       ...because it uses `Self` as a type parameter
28  |     + ops::Mul<Output = Self>
    |       ^^^^^^^^^^^^^^^^^^^^^^^
    |       |        |
    |       |        ...because it uses `Self` as a type parameter
    |       ...because it uses `Self` as a type parameter
29  |     + ops::Div<Output = Self>
    |       ^^^^^^^^^^^^^^^^^^^^^^^
    |       |        |
    |       |        ...because it uses `Self` as a type parameter
    |       ...because it uses `Self` as a type parameter
30  |     + ops::AddAssign + ops::SubAssign + ops::MulAssign + ops::DivAssign
    |       ^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter
    |       |                |                |
    |       |                |                ...because it uses `Self` as a type parameter
    |       |                ...because it uses `Self` as a type parameter
    |       ...because it uses `Self` as a type parameter
    |
   ::: /Users/~~/.cargo/registry/src/github.com-1ecc6299db9ec823/cauchy-0.2.2/src/lib.rs:44:7
    |
44  |     + Sum
    |       ^^^ ...because it uses `Self` as a type parameter
45  |     + Product
    |       ^^^^^^^ ...because it uses `Self` as a type parameter
    |
   ::: /Users/~~/.cargo/registry/src/github.com-1ecc6299db9ec823/num-traits-0.2.14/src/lib.rs:67:41
    |
67  | pub trait Num: PartialEq + Zero + One + NumOps {
    |                ^^^^^^^^^                ^^^^^^ ...because it uses `Self` as a type parameter
    |                |
    |                ...because it uses `Self` as a type parameter
...
149 | pub trait NumAssign: Num + NumAssignOps {}
    |                            ^^^^^^^^^^^^ ...because it uses `Self` as a type parameter
    |
   ::: /Users/~~/.cargo/registry/src/github.com-1ecc6299db9ec823/num-traits-0.2.14/src/identities.rs:12:25
    |
12  | pub trait Zero: Sized + Add<Self, Output = Self> {
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^
    |                         |         |
    |                         |         ...because it uses `Self` as a type parameter
    |                         ...because it uses `Self` as a type parameter
...
90  | pub trait One: Sized + Mul<Self, Output = Self> {
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^
    |                        |         |
    |                        |         ...because it uses `Self` as a type parameter
    |                        ...because it uses `Self` as a type parameter

Upvotes: 1

Views: 984

Answers (1)

rodrigo
rodrigo

Reputation: 98486

Your Type is not actually a data type but a trait. And when you write an impl for a trait, you are actually writing it for the dyn object version of that trait, and that is not usually what you want. In fact you probably are getting a warning like:

warning: trait objects without an explicit `dyn` are deprecated

The rest of the errors arise because your trait requirements are not dyn-object safe.

What you probably need is a simple function in the trait:

pub trait Type: Lapack + Scalar + Float + Sync + Send {
    fn abs(&self) -> Self;
}
impl Type for f32 {
    fn abs(&self) -> Self {
        Self::abs(*self)
    }
}
impl Type for f64 {
    fn abs(&self) -> Self {
        Self::abs(*self)
    }
}

Yes, you have to repeat the code for every type that implements the Type but for this case it is barely an inconvenience.

If there are a lot of types and a lot of functions you can use macros, that is what most libraries do.

Upvotes: 1

Related Questions