That's because it tends to be wonky and end up in tears as you try to find out what the source of the corruption (the original creator of the error) is. NaN is emblematic of that, as it's usually undesirable and you'd much rather have received an error instead of gotten nonsense injected in your program state.
Objective-C has this, where errors would usually end up returning a `nil` (with an NSError accessible via an optional out parameter), and sending a message to `nil` has no effect and returns `nil`, so you could code on the happy path and end up with no idea whatsoever why your thing stops working, with the only information being that you end up with a `nil`.
libc error handling also kinda but kinda not uses this pattern, with the additional fun that you can UB on the way: libc does not normally reset errno, so you can reset it (to 0), call a bunch of functions, and check errno at the end.
Except that doesn't really work because:
1. not all functions will signal errors via errno
2. third-party code may be resetting errno for its own use (errno is not unlike a caller-saved register in that sense)
3. third party code may handle errno internally, but will not reset it if so, leading to sprurious error messages.
Objective-C has this, where errors would usually end up returning a `nil` (with an NSError accessible via an optional out parameter), and sending a message to `nil` has no effect and returns `nil`, so you could code on the happy path and end up with no idea whatsoever why your thing stops working, with the only information being that you end up with a `nil`.
libc error handling also kinda but kinda not uses this pattern, with the additional fun that you can UB on the way: libc does not normally reset errno, so you can reset it (to 0), call a bunch of functions, and check errno at the end.
Except that doesn't really work because:
1. not all functions will signal errors via errno
2. third-party code may be resetting errno for its own use (errno is not unlike a caller-saved register in that sense)
3. third party code may handle errno internally, but will not reset it if so, leading to sprurious error messages.