0

I want to use the following code:

use std::ops::Rem;

fn modulo<T: PartialOrd + Rem>(num: T, det: T) -> T {
    let num = num % det;
    if num < 0.0 {
        num + det.abs()
    } else {
        num
    }
}

This is just generalized code taken from the experimental euclidean_division feature. The error provided is along the lines of:

error[E0369]: binary operation `<` cannot be applied to type `<T as std::ops::Rem>::Output`
 --> src/lib.rs:5:8
  |
5 |     if num < 0.0 {
  |        ^^^^^^^^^
  |
  = note: an implementation of `std::cmp::PartialOrd` might be missing for `<T as std::ops::Rem>::Output`

error[E0599]: no method named `abs` found for type `T` in the current scope
 --> src/lib.rs:6:19
  |
6 |         num + det.abs()
  |                   ^^^

error[E0369]: binary operation `+` cannot be applied to type `<T as std::ops::Rem>::Output`
 --> src/lib.rs:6:9
  |
6 |         num + det.abs()
  |         ^^^^^^^^^^^^^^^
  |
  = note: an implementation of `std::ops::Add` might be missing for `<T as std::ops::Rem>::Output`

error[E0308]: mismatched types
 --> src/lib.rs:8:9
  |
3 | fn modulo<T: PartialOrd + Rem>(num: T, det: T) -> T {
  |                                                   - expected `T` because of return type
...
8 |         num
  |         ^^^ expected type parameter, found associated type
  |
  = note: expected type `T`
             found type `<T as std::ops::Rem>::Output`

Obviously the output of Rem::rem should be the same type as T, but the compiler doesn't know that, I assume.

Is there a way to solve this issue, or should I just implement it per type the same way it does in the nightly edition?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
flmng0
  • 387
  • 1
  • 2
  • 14

1 Answers1

3

Generics with primitives is not so simple. Fixing the first error reveals other errors because you compare T with 0.0. There are many ways to fix these problems; here's one way using num:

use num::{Signed, Zero};
use std::ops::Rem;

fn modulo<T>(num: T, det: T) -> T
where
    T: Rem<Output = T>,
    T: PartialOrd,
    T: Zero,
    T: Signed,
    T: Copy,
{
    let num = num % det;
    if num < T::zero() {
        num + det.abs()
    } else {
        num
    }
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Stargateur
  • 24,473
  • 8
  • 65
  • 91
  • The 0.0 is an artifact from just implementing it for f32. Forgetting about it made the issue much more difficult. This answer works perfectly, however. So thank you very much for your fast reply. – flmng0 Apr 13 '19 at 15:10