(original) (raw)


On Mar 24, 2010, at 2:31 PM, Alexander Belopolsky wrote:

"""
In this context it doesn't particularly shock me that operations on
NaN should cause invariant violations. After all, isn't NaN supposed
to mean "not a number"? If it's not a number, it doesn't have to
satisfy the properties of numbers.
"""

This sound like a good, universal reply to "bug reports" about
various containers/tools not working with NaNs :-)

Bug report: "Container X or Function Y doesn't behave well when I
give it a NaN as an input".

Closed -- Won't fix:  "It does not shock me that a NaN violates that
tool or container's invariants."


To bring the discussion back on topic for python-dev, I would argue
that reflexivity should hold for hashable values.  Having it otherwise
would lead to unsurmountable problems when storing such values in sets
or using them as keys in dictionaries.  If x == x is False stays for x
= float('nan'), I would argue that hash(float('nan')) should raise
NotImplemented or ValueError.

Hashability isn't the only place where you have a problem.
Even unordered collections are affected:

  >>> class ListBasedSet(collections.Set):
     ''' Alternate set implementation favoring space over speed
         and not requiring the set elements to be hashable. '''
     def \_\_init\_\_(self, iterable):
         self.elements = lst = \[\]
         for value in iterable:
             if value not in lst:
                 lst.append(value)
     def \_\_iter\_\_(self):
         return iter(self.elements)
     def \_\_contains\_\_(self, value):
         return any(value == elem for elem in self.elements)
     def \_\_len\_\_(self):
         return len(self.elements)

        
>>> n = float('Nan')
>>> s = ListBasedSet(\[n\])
>>> n in s                 # unexpected result
False
>>> len(s)                # expected result
1
>>> len(s & s)         # unexpected result
0

If we want to be able to reason about our programs,
then we need to rely on equality relations being
reflexsive, symmetric, and transitive.  Otherwise,
containers and functions can't even make minimal 
guarantees about what they do.

Anything else smells of a Douglas Hofstadter style
or Betrand Russell style logic bomb:

\* this sentence is a lie
\* this object isn't equal to itself
\* this is a set containing sets that are not members of themselves

The property of NaN objects not being equal to themselves
is more harmful than helpful.  We should probably draw the
line at well-defined numeric contexts such as the decimal module
and stop trying to propagate NaN awareness throughout the
entire object model.


Raymond