It would be possible to have a safe float without the need of extensive runtime checks, but that would require rethinking floats.
We could define the float division operator with non-nan, finite, non-zero operand types, like for example fn div(a: FiniteNumber, b: FiniteNonZeroNumber), which would guarantee never-failing division at compile time. Apart from being ergonomic and bug-preventing, that would also allow for massive compiler optimizations. Runtime checks would only be necessary where a FiniteNumber is converted into FiniteNonZeroNumber, basically checking if the dividend is zero.
powf(base: FiniteNumber, exp: FinitePositiveNumber), would also be possible.
Division may look like this:
average_age = (a.age + b.age) / 2 and you’d know that this can’t be NaN and it can’t be infinity because a.age and b.age are finite numbers.
We could do conversion like iter().sum() / n.expect_non_zero() where the divisor is expected to be non null, but the type system cannot guarantee it. ‘expect non zero’ would panic if the number is zero.
Of course this approach would be rather explicit. Also, it does not handle the addition two numbers where the sum is too large to be stored in a float. This could be handled like integer overflow, panicking in debug mode and returning NaN in release mode.