// This code compiles, prints 12
fn f1() void {
var a: u8 = 10.0;
a += 2.0;
print("{}", .{a});
return 0;
}
// This code does not compile
fn f2() void {
var a: u8 = 10.0;
a += 2.1;
print("{}", .{a});
return 0;
}
I understand that Zig does not allow 2.1 to be coerced to u8 in f2. What I don’t understand is why it’s allowed allows comptime_float to be coerced to a u8 in f1, as long as that float does not have a fractional part.
At compile time Zig will allow any numeric coercion to happen as long as the value fits the target type without losing precision, here are 2 more examples:
const x: f32 = 16.0;
// Here sqrt complained that it cannot work with usize result type
// using floats is the only way to square-root an integer at compile time.
const y: usize = @as(f32, @sqrt(x));
const z: i32 = y;
@compileLog(z); // 4
Often this reduces friction since you don’t need to worry about additional casts.
Good point regarding Rust: the compiler does consider all floating point literals to be f64 unless they are explicitly typed or inferred. So that comparison was admittedly useless, sorry.
Regarding your “Why not” point, what I meant was: “Why allow this sort of exception, where x.0 is allowed to be cast into integers, but x.1 is not? What’s the rule that is being followed?”. @IntegratedQuantum ‘s response clears it up perfectly! Zig will always allow cast from one numeric type to another, as long as this cast can happen without precision loss!
This only applies to comptime arithmetic. (Your reply reads as if perhaps you missed that). Zig certainly won’t perform such casts on runtime values; you’ll get a compile error instead. If you’re running this in a test function, try declaring your float as var instead of const and see what happens.