How to constrain a generic argument with Index trait

I'm writing a generic function:

pub fn sort_by_axis<T>(data: &mut Vec<T>, ind: usize) {
}

that sorts the given data by ind-th coordinate. How to constraint the type T to define that T[i] returns a Float type?

where <T as Index>::Ouput: Float

Well, the compiler says:

error[E0576]: cannot find associated type `Ouput` in trait `Index`
 --> src/main.rs:5:21
  |
5 | where <T as Index>::Ouput: Float {
  |                     ^^^^^ help: an associated type with a similar name exists: `Output`
 --> /rustc/9eb3afe9ebe9c7d2b84b71002d44f4a0edac95e0/library/core/src/ops/index.rs:62:5
  |
  = note: similarly named associated type `Output` defined here

Here is the playground:

This looks like a spelling mistake to me, Ouput is not an associated type of Index, but Output is :wink:

There is also another trait bound (T: Index<usize>) and a generic parameter for Index missing. Here a version of your code that compiles:

use num_traits::Float;
use std::ops::Index;

pub fn sort_by_axis<T>(data: &mut Vec<T>, ind: usize)
where
    <T as Index<usize>>::Output: Float,
    T: Index<usize>,
{
}

fn main() {
    let mut data = vec![vec![0.0, 0.5], vec![0.7, 0.5], vec![0.8, 1.1]];
    sort_by_axis(&mut data, 1);
}

Playground.

Thanks! Now it works. But to finish that function I have to write the code that actually sorts. I've tried:

use std::ops::Index;
use num_traits::Float;

pub fn sort_by_axis<T>(data: &mut Vec<T>, idx: usize) 
where <T as Index<usize>>::Output: Float, T: std::ops::Index<usize> {
    data.sort_by(|a,b| b[idx].partial_cmp(&a[idx]));
}


fn main() {
    let data = vec![vec![0.0, 0.5], vec![0.7, 0.5], vec![0.8, 1.1]];
    sort_by_axis(&mut data,1);
}

but I got:

error[E0308]: mismatched types
 --> src/main.rs:6:23
  |
6 |     data.sort_by(|a,b|b[idx].partial_cmp(&a[idx]));
  |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Ordering`, found enum `Option`
  |
  = note: expected enum `std::cmp::Ordering`
             found enum `Option<std::cmp::Ordering>`

Welcome to the strange world of float comparisons. You need to unwrap the result of partial_cmp, because comparing floats is not that simple, i.e. NaN != NaN.

data.sort_by(|a,b| b[idx].partial_cmp(&a[idx]).unwrap());

See e.g. this topic:

@H2CO3 recently shared a helpful link with more information about float comparisons, but unfortunately I don't recall which topic it was, nor do I remember the webpage.

1 Like

I think it was this one.

1 Like

Yes, thanks for re-sharing!