5 ms·
sqrt(-1.0) is NaN, it's typically used in numerical code where you can't stop and check for exceptions because performance is key. But just for the sake of arg
by qsort 6y ago
sqrt(-1.0) is NaN, it's typically used in numerical code where you can't stop and check for exceptions because performance is key.
But just for the sake of argument, the type of 'sqrt' isn't:
sqrt : R -> R
it is:
sqrt : R+ -> R+
So you have two options here. You can have sqrt return "Either Error Double" and force the programmer to deal with the possibility of an error (Rust does this) or you define a "nonnegative real" type that the compiler can guarantee will be an acceptable input for sqrt. The latter is much harder to do.
But either way no, you only need an "out of band" mechanism when the type system isn't strong enough or isn't being properly leveraged.
- mikewarot 6y agoI used square root because it is commonly known that negative numbers are a problem for them. What about tangent(x) which periodically blows up? A type system can't fix that. In my opinion it is far better to throw an exception that can be explicitly handled, rather than cause some math error at some random point later because NaN or some infinity snuck by as a number.
- qsort 6y agoMath.tan will never throw exceptions because, for the exact same reason as above, it won't check its input. But again for the sake of argument, the return type of tan() could be "Either<Error, double>".
- mikewarot 6y agoI guess I would get used to that, but it seems broken to me. The way to deal with that is out of band, checking for the type to change to "Error" In Pascal tan(pi/2) or tan(3pi/2) causes an overflow. The way to deal with that is out of band, to handle an exception of type E_Overflow.
- qsort 6y agoAgain no, it isn't. You are well entitled to believe Pascal is the best thing since sliced bread, but the two ideas are fundamentally different. There is no type change. The function "tan" would return a value of type "Either<Error, double>". An expression such as: double x = Math.tan(Math.PI / 8) would fail the compile-time type check, because the type of the variable "x" is "double" and the type of the expression "Math.tan(Math.PI / 8)" is "Either<Error, double>". It would be the responsibility of the caller to prove to the type system that the error has been handled, with either a built-in language facility a la ML, or with ad-hoc code such as a Bohm-Berarducci construction. Let's just agree to disagree.
- mikewarot 6y agoI know Pascal isn't perfect, and lots has been learned since then... this is genuine confusion on my part. So tan in your system returns a variant type (could be Error, could be Double), right? (I didn't get that) Compilers can find all sorts of things they couldn't in the past, which is amazing. What happens at run-time if an overflow happens? again... I'm sorry if I didn't express myself clearly enough. I'm coming at this from a Pascal programmers perspective... I've missed the past 20 years of compiler improvements.
- setr 6y agoRust chooses to panic, I believe, but you could always have applied the same Error strategy — it’d just be really annoying. The stdlib also provides a bunch of methods to pick-your-strategy for overflow behavior, but you need to use them instead of the +/* operation
- SAI_Peregrinus 6y agoIn Rust in particular (and many other languages) tan operates on IEEE 754 double-precision floating points ("double" for Free Pascal, "f64" for Rust). These can contain infinity and NAN values, not just numbers. So if tan blows up, you get NAN back. It's your job as the programmer to check that the result wasn't NAN (or INF) before proceeding. "Double" is already such a variant type. So you have to check your results which can return an error variant for errors, just like you already do with floating-point values.
- hedora 6y agoSqrt(-1.0) should return NaN or raise a signal. Let the programmer choose. Throwing an exception doesn’t help anyone.