Function call breaks when called within certain other functions

Hello.

I'm implementing a Percentile function which requires also a linear interpolation function. I'm aiming to make them generic for integers and floats. The interpolation function works fine when called from it's test but breaks compilation when called from the percentile function.

pub fn interpolate_linear<T: Add<Output=T> + Sub<Output=T> + Debug + Copy>(a: &T, b: &T, how_far_from_a_to_b: f64)  -> f64 
    where f64: From<T> {
    let a = f64::from(*a);
    let b = f64::from(*b);
    a + (how_far_from_a_to_b * (b - a))
}
pub fn percentile<T: Add<Output=T> + Sub<Output=T> + PartialOrd + Debug + Copy>(data_set: &Vec<T>, n: f64) -> f64 where f64: From<T> {
    let rank = n * (data_set.len() as f64 -1f64) + 1f64;
    println!("Rank = {}", rank);
    let below = rank.floor() as usize;
    let above = rank.floor() as usize + 1;
    let lower_value = f64::from(data_set[below]);
    let higher_value = f64::from(data_set[above]);
    interpolate_linear(&lower_value, &higher_value, n);
}

And the error this produces is:

error[E0308]: mismatched types
  --> src/statistics.rs:21:24
   |
21 |     interpolate_linear(&lower_value, &higher_value, n)
   |                        ^^^^^^^^^^^^ expected type parameter, found f64
   |
   = note: expected type `&T`
              found type `&f64`

error[E0308]: mismatched types
  --> src/statistics.rs:21:38
   |
21 |     interpolate_linear(&lower_value, &higher_value, n)
   |                                      ^^^^^^^^^^^^^ expected type parameter, found f64
   |
   = note: expected type `&T`
              found type `&f64`

I have the following test which works fine:

#[test]
    fn test_interpolate_with_f32() {
        let result = interpolate_linear(&3f32, &5f32, 2f64);
        println!("test_interpolate_with_i32 result: {:?}", result);
        assert_eq!(result, 7f64);
    }

What gives? :slight_smile:

  1. There's an extra semicolon in the last line of fn percentile.

  2. I'm not sure whether it's some quirk in type resolution or a deliberate design decision, but you can force the compiler to use the f64 version of interpolate_linear by writing:

interpolate_linear::<f64>(&lower_value, &higher_value, n)

There are other cases when the "Expected type parameter" error is reported, but they usually involve returning a concrete type from a generic function.

I'd venture this is some quirk (bug?) of type resolution, as @inejge mentioned . Namely, I've seen this type of thing when you're working in the context of generic functions but then convert to a concrete type in the middle, and pass that concrete type to another generic function. You can file an issue in rust's github repo and see what comes of it (likely a known issue, so try searching a bit first).

That said, you can simplify your code and sidestep this whole issue with:

...
let lower_value = data_set[below];
let higher_value = data_set[above];
interpolate_linear(&lower_value, &higher_value, n)

i.e. there's no reason to convert to f64 before calling interpolate_linear - this keeps the code generic, and avoids the quirk.

1 Like

Thanks all. I think the f64::from was a desperate move to try to get it to compile :grin: I'm pretty sure this is a bug though, because if I call:

interpolate_linear(1.0,2.0,0.5);

from the percentile function, I still get an error:

error[E0308]: mismatched types
  --> src/business_logic/statistics.rs:21:24
   |
21 |     interpolate_linear(1.0,2.0,0.5);
   |                        ^^^ expected &T, found floating-point variable
   |
   = note: expected type `&T`
              found type `{float}`

But if called the same way from within another function it works.

I'll search for similar issues on Github and if I can't find anything similar I'll open a new one, giving an example repo to show the problem. I'll update this thread with what comes of it.

Thank you both!