Default type for float

Hi there....

let x = 2.0;

here official doc says that x is float64 by default

println!("{}", x.trunc());

but here compiler complains:

can't call method trunc on ambiguous numeric type {float} let x = 2.0;
and suggests

you must specify a type for this binding, like f32

why trunc does not refer to inferred type?

thx.

The default doesn't always apply. In this case, the compiler backs off to let you be explicit because f32::trunc and f64::trunc have different return types.

Yes, I understood. What is not clear, at least to me, is why the default is not applicable here and, in general, in which cases this situation can occur.
Thx again

This is a known shortcoming of the current type inference implementation. Some operations require a type to be known immediately at a point in the program, and that might not be the case, even if inference would later result in the type getting inferred correctly (either through other constraints in the function or via fallback to f64).

Maybe I haven't really fully understood the spirit of Rust yet but it seems to me a really ambiguous and even a little dangerous behavior

use std::any::type_name;
fn type_of<T>(_: T) -> &'static str {
type_name::<T>()
}

fn main() 
{        let y = 2.5;
         println!("{}", type_of(y));
  //     println!("{}", y.trunc()) --ERROR
}

Compiler knows what x is but trunc() cannot resolve
It seems very inconsistent to me,,, I probably have to study some more
Cheers

If you just write 1.0 rustc will do any of the following

  • infer the type if possible
  • assume generic float and end up using whatever is the default (currently f64)
  • give up and complain

To make sure you know what happens, just write 1.0f32 instead.

What is dangerous about that behavior?

Dangerous because unexpected, at least from the point of view of those new to the language. Not a big deal now that I know, and the error message certainly helps, but I would have expected if the compiler knows the type it won't ask me anymore.

You may be under the impression that rustc decided (or "knew") y was f64 once it got to println!("{}", type_of(y)) but still complained as it continued on to println!("{}", y.trunc()). However, that's not how inference works with rustc. Code later in the function can be used to infer types earlier in the functions.

In other words, when it errorred, it didn't know the type. It decided that the function as a whole was too ambiguous to decided on which type to use, and gave up. Sometimes you have to help it along.

For example, in the code below, it chooses f32 as that's the only thing that matches nudge_inference(y). type_of(y) prints "f32" even though it came before nudge_inference(y) in the code. Everything as a whole is consistent.

use std::any::type_name;
fn type_of<T>(_: T) -> &'static str {
    type_name::<T>()
}

fn nudge_inference(x: f32) -> f32 {
    x * 2.0
}

fn main() {
    let y = 2.5;
    println!("{}", type_of(y));
    println!("{}", nudge_inference(y));
}

If you find it too confusing, you can always just be explicit about your types.

1 Like

Interesting.... i have to play a bit with this.

Tk u all.