https://github.com/microsoft/GSL/issues/786#issuecomment-513...
> I'll raise this issue in the next internal GSL sync. I'd agree with y'all that this behavior: https://godbolt.org/z/4Tr1fe9xG is undesirable
https://github.com/microsoft/GSL/issues/786#issuecomment-513...
> I'll raise this issue in the next internal GSL sync. I'd agree with y'all that this behavior: https://godbolt.org/z/4Tr1fe9xG is undesirable
The problem isn't, "oh no what if my CPU's float->int conversion instruction traps", that's an extremely naive way to think about UB. Everyone who has thought seriously about UB in C++ for any length of time knows this. It's worrying that this was Sutter's response.
The natural instinct of humans is to deny problems. Their safety culture very strongly encourages Rustaceans encountering the equivalent issue [this really happened, you could write this nasty conversion bug in Rust 1.0 no problem but for years now Rust panics] to accept that there is a safety problem - and from there they can begin actually addressing the problem rather than pretending it doesn't exist. It's not perfect, but the alternatives are definitely worse.
The technology doesn't do this. The Rust compiler would be entirely OK with Rust shipping a standard library where safe APIs like Vec::pop can induce Undefined Behaviour. That's not allowed culturally, but technically Vec::pop already has an unsafe block, it could cause UB if it wanted to.
This case also shows the limits of Rust's safety culture; they knew about the problem for a long time, and could have fixed it right away if they'd been willing to make programs that do a lot of float-to-int casts eat a performance regression, but a number of users objected strongly to this. So it remained unfixed until they figured out a way to make it fast enough that no one would really notice.
Yes sorry, in my head I'm thinking about what I'd want here because I do not like any of Rust's 'as' casts and in fact the thing I'd want here (TryInto) just does not exist on purpose for this reason. I wonder if I've ever run into this, realised I can't write a TryInto and if so what did I end up doing - interesting.
My `Rational` type is the "big rationals" (the finite subset of rational numbers I can represent with your available RAM) and these are certainly able to precisely represent any 32-bit or 64-bit float which isn't NaN or an infinity. However, vice versa is not true of course. 0.1 is a very easy Rational, but of course binary floating point cannot represent this exactly.
In the end I punted, TryInto<Rational> is implemented for f32 and f64 but the opposite is not provided at all.
Like I said, safety is cultural. You can invent this stuff, somebody did, but the way most people end up doing it isn't because they all spontaneously invented the same solution, it was absorbed from their culture. C++ culture says "Don't do that" all the time instinctively. An actual concrete objection to fixing it might be offered if you insist on one, but they start with "Don't do that".
Sorting is my go-to example. Rust's sorts are safe. If I sort "Alligator", "Baboon", "Cat", "Donkey" then no matter what my ordering rule was nothing crazy happens. If my rule was nonsense, like "Every item is before every other item" then Rust might panic, it is allowed to do that - but otherwise it just will give me back the same four items but who knows what order because my ordering rule is nonsense. That seems easy enough, right?
In C++ if my ordering rule does not meet the precise requirements of the C++ language then all bets are off, that's Undefined Behaviour. I might get back "Cat", "Cat", "Cat", "Cat" even though there was originally only a single cat, or it might scribble past the end of my list of animals, crash, or anything at all. And while it would be permissible for real C++ standard library implementations to do better, on the whole they don't. "Don't do that" is the answer if you ask why this defect is allowed.