[Python-Dev] RE: Rich comparisons [Was] redefining is

Tim Peters tim.one at comcast.net
Sun Mar 21 01:26:10 EST 2004


[Raymond Hettinger]
> ...
> Essentially, I would like to insert the following lines into
> PyObject_RichCompare():
>
> 	if (v == w) {
> 		if (op == Py_EQ)
> 			Py_RETURN_TRUE;
> 		else if (op == Py_NE)
> 			Py_RETURN_FALSE;
> 	}

At the sprint today, Armin Rigo pointed out that this specific kind of
change is a non-starter:  rich comparisons aren't constrained to return
bools.  In fact, that's primarily why they were introduced, so that the
array extensions to Python could have (e.g.)

    array1 == array2  # assuming same shapes

return an array of true/false values (recording elementwise equality of
corresponding array elements).  "array1 is array2" can't cause a special
case returning a scalar then.

So that's right out.

OTOH, the changes we've made to recursive compares in 2.4 are causing Armin
some grief, particularly wrt dicts that may be reachable from themselves.
Doing, e.g.,

>>> d = {}
>>> d[1] = d
>>> d == d

returns True in 2.3.3, but raises

    RuntimeError: maximum recursion depth exceeded in cmp

in current CVS.

While PyObject_RichCompare() can't make any assumption about the return
type, PyObject_RichCompareBool() can, and inserting

    x is y
implies
    (x == y) is True

in the latter remains possible.

Armin and Guido and I agreed it's OK if

>>> x = some_NaN
>>> x == x
True
>>>

happened as a result.  Also that we're *willing* to insist that "x is y"
implies "x == y" regardless of type in PyObject_RichCompareBool().  But
since "x == x" doesn't normally invoke PyObject_RichCompareBool, the
willingness to infer equality from identity in the latter may have no effect
on NaN comparisons.

WRT the NaN business, Python doesn't have a real 754 story now, and what
we've done so far in 2.4 to back into a teensy part of one by contrived
accident isn't worth preserving.  If we were serious about this, I'd argue
until everyone gave up <0.4 wink> that "naive comparisons" involving NaNs
should raise an exception, and that the 32(*) possible 754 comparisons be
supplied via a wordier spelling (there are 16 depending on which subset of
{less, equal, greater, unordered} you're asking about, and then each of
those comes in two flavors, one that raises an exception if at least one
comparand is a NaN, and another that doesn't -- "==", "<", "<=", ..., would
then map to 6 of the first flavor, leaving 26 that could only be gotten via
a wordier spelling).

I'd like Armin to share enough details here about the cases causing him
grief now so that we can all guess whether that kind of change to
PyObject_RichCompareBool would be enough to make life happy again.



(*) Note that not all 32 possibilities are actually useful; e.g., one
    of them always returns True, another always False.  Similarly,
    when unordered isn't a possible outcome, there are 6 non-empty
    proper subsets of {less, equal, greater}, and that's where the 6
    comparison operators "we're used to" come from (the {less, greater}
    subset being the "not equal" operator, which is screamingly
    obvious from its deprecated "<>" spelling).




More information about the Python-Dev mailing list