[Python-Dev] Std test failures on WIndows: test_compare, test_minidom

Tim Peters tim.one@home.com
Tue, 2 Jan 2001 19:30:26 -0500

> They do on my box:
>     Python 2.0 (#19, Nov 21 2000, 18:13:04)
>     [GCC 2.95.2 20000220 (Debian GNU/Linux)] on linux2
>     Type "copyright", "credits" or "license" for more information.
>     >>> cmp(1, None)
>     -78

Well, who cares about your silly box <wink>?  Messier than I thought!  Yes,
Windows strcmp is always in {-1, 0, 1}.  Rather than run tests, here's the
tail end of MS's strcmp.c:

        if ( ret < 0 )
                ret = -1 ;
        else if ( ret > 0 )
                ret = 1 ;

        return( ret );

Wasted cycles and stupid formatting <wink>.

> ...
> AFAICT, the problem is that instances without a comparison method can
> compare larger or smaller than numbers depending on where in memory
> the objects are stored.

If so, that's a bug ... OK, it *is* a bug, at least in current CVS.  Did you
cause that, or was it always this way?  I was able to provoke this badness:

>>> j < c < i
>>> j < i

i.e. it violates transitivity, and that's never supposed to happen in the
absence of user-supplied __cmp__.  Here c is an instance of "class C: pass",
and i and j are ints.

>>> type(i), type(j), type(c)
(<type 'int'>, <type 'int'>, <type 'instance'>)
>>> i, j, c
(999999, 1000000, <__main__.C instance at 00791B7C>)
>>> id(i), id(j), id(c)
(7941572, 7744676, 7936892)

Guido thought he fixed this kind of stuff once (and I believed him <wink>)
by treating all numbers as if they had type name "" (i.e., yes, an empty
string) when compared to non-numbers.  Then the usual "mixed-type
comparisons in the absence of __cmp__ compare via type name string" rule
ensured that numbers would always compare "less than" instances of any other
type.  That's the intent of the tail end:

		else if (vtp->tp_as_number != NULL)
			vname = "";
		else if (wtp->tp_as_number != NULL)
			wname = "";
		/* Numerical types compare smaller than all other types */
		return strcmp(vname, wname);

of PyObject_Compare.  So, in the example above, we *should* have

    i < c == 1
    j < c == 1
    j < c < i == 0

Unfortunately, we actually have

    i < c == 0

in that example.  We're apparently not getting to the "number hack" code
because c is an instance, and I'll confess up front that my eyes always
glazed over long before I got to PyInstance_HalfBinOp <0.half wink>.
Whatever, there's at least one bug somewhere in that path!   We should have
n < i == 1 for any numeric type n and any non-numeric type i (in the absence
of user-defined __cmp__).