On Sun, Jul 5, 2020 at 8:57 AM Steven D'Aprano <steve@pearwood.info> wrote:

In the absense of any clear winner, my position is that NAN poisoning
should be opt-in. We should pick the option which inconveniences people
who want the other the least .

Let's say the stdlib uses Option 1. The function doesn't need to do any
explicit checks for NANs, so there's no problem with large integers
overflowing, or Decimals raising ValueError, or any need to do a
conversion to float.

People who want NAN poisoning can opt-in by doing a check for NANs
themselves, either in a wrapper function, or by testing the bounds
*once* ahead of time and then just calling the stdlib `clamp` once they
know they aren't NANs.

Imagine making the same statement about exceptions:

 Exceptions being raised should be opt-in. 

That sounds crazy but it's not. Before exceptions were commonplace, there were three possibilities when unreasonable operations were performed:
Things are much better now. Few argue that it was better before. Think of NaN as the value equivalent of an exception. NaN poisoning is the equivalent of the fact that any function that doesn't catch an exception passes it through. I don't usually write code that uses NaNs directly. If I want a distinguished non-numeric value, I use None or some other sentinel. If a NaN is produced by my code it indicates a bug. NaN poisoning increases the chance that a NaN generated somewhere won't be hidden by later code that manipulates that value. Why would I want to suppress that?

Just as an exception can be suppressed by explicit code, Nan poisoning can be suppressed by explicit checks. So let me rewrite your second and third paragraphs above (recall Option 1 which you favor is ignore NaNs, and Option 2 is NaN poisoning):

Let's say the stdlib uses Option 2. The function doesn't need to do any
explicit checks for NANs, so there's no problem with large integers
overflowing, or Decimals raising ValueError, causing errors that don't get noticed,
or any need to do a conversion to float.

People who don't want NAN poisoning can opt-out by doing a check for NANs
themselves, either in a wrapper function, or by testing the bounds
*once* ahead of time and then not calling the stdlib `clamp` once they
know they are NANs.

This is a better argument. People that use NaNs and expect them write code to handle it. The rest of us don't want to be surprised by suppressed errors.

--- Bruce