Re:Operator constraints in Go
by dinosaurdynasty on Monday May 23, 2022 @04:23PM
(#31484367)
Rust handles this in a "correct", if annoying way: the stdlib sort requires its elements to have a "totally ordered" trait, and floating point doesn't have that trait. You have to either give a custom comparison function, or use a "non-NaN and totally orderable floating point" type some non-stdlib crates have.
This perfectly illustrates the cultural difference between Rust and Go: Rust wants to be "correct", Go wants to be "good enough".
This is problematic even in dependently-typed languages like Idris, because while you can require a proof that something is not (or does not contain) NaN, it's pretty easy to call a function that is allowed to return NaN, which means that you actually cannot satisfy that proof after calling one of those functions unless you actually check again.
The entire C++ STL is a huge footgun for this very reason. None of the algorithms work on floats unless you guarantee the absence of NaN (which the STL assumes without being terribly vocal about it).
Note in the second case, that's not "Go" sorting NaNs to the front, that's the requested result from the passed-in function. You could create any result you wanted with a suitable choice of such function.
This isn't particularly special to Go. Most languages have "quirks", to put it charitably, around floats. Even Haskell would have similar behavior. It's really the IEEE standard that is broken, arguably; defining an entity that is not equal to itself proceeds to effectively break a huge swathe of things that you may not have even realized was based on the presumption that the identity property holds, because... why would you think about what is based on that? It's so foundational. As anyone who has dealt with NaNs for any period of time can attest, it's really difficult to work with such entities.
(Similarly, while I understand what they were trying to get at, I think SQL NULL should be equal to itself. I could be down with NULL < 1 being false and NULL > 1 being false but I'm not a huge fan of how it's NULL either. We've had many languages written since then with more conventional ideas about "invalid" values and how they participate in operators and I think the modern way almost everything else works is better, even if it arguably less "correct".)