[Python-checkins] CVS: python/nondist/peps pep-0207.txt,1.8,1.9

Guido van Rossum gvanrossum@users.sourceforge.net
Fri, 19 Jan 2001 14:29:21 -0800


Update of /cvsroot/python/python/nondist/peps
In directory usw-pr-cvs1:/tmp/cvs-serv15427

Modified Files:
	pep-0207.txt 
Log Message:
Finalized this PEP.  Closed all unresolved issues.


Index: pep-0207.txt
===================================================================
RCS file: /cvsroot/python/python/nondist/peps/pep-0207.txt,v
retrieving revision 1.8
retrieving revision 1.9
diff -C2 -r1.8 -r1.9
*** pep-0207.txt	2000/12/06 21:22:52	1.8
--- pep-0207.txt	2001/01/19 22:29:19	1.9
***************
*** 4,8 ****
  Author: guido@python.org (Guido van Rossum), DavidA@ActiveState.com (David Ascher)
  Python-Version: 2.1
! Status: Incomplete
  
  
--- 4,8 ----
  Author: guido@python.org (Guido van Rossum), DavidA@ActiveState.com (David Ascher)
  Python-Version: 2.1
! Status: Final
  
  
***************
*** 30,35 ****
      an arbitrary ordering, just so that equality can be tested.
  
!     More motivation can be found in the proposals listed under
!     previous work below.
  
  
--- 30,37 ----
      an arbitrary ordering, just so that equality can be tested.
  
!     Also, for some object types an equality test can be implemented
!     much more efficiently than an ordering test; for example, lists
!     and dictionaries that differ in length are unequal, but the
!     ordering requires inspecting some (potentially all) items.
  
  
***************
*** 77,95 ****
  
      1 Full backwards compatibility can be achieved as follows.  When
!       an object defines tp_compare() but not tp_richcmp(), and a rich
!       comparison is requested, the outcome of tp_compare() is used in
!       the ovious way.  E.g. if "<" is requested, an exception if
        tp_compare() raises an exception, the outcome is 1 if
        tp_compare() is negative, and 0 if it is zero or positive.  Etc.
  
!       Full forward compatibility can be achieved as follows.  (This is
!       a bit arbitrary.)  When a classic comparison is requested on an
!       object that only implements tp_richcmp(), up to three
!       comparisons are used: first == is tried, and if it returns true,
!       0 is returned; next, < is tried and if it returns true, -1 is
!       returned; next, > is tried and if it returns true, +1 is
!       returned.  Finally, TypeError("incomparable objects") exception
!       is raised.  If any operator tried returns a non-Boolean value
!       (see below), the exception is passed through.
  
      2 Any type that returns a collection of Booleans instead of a
--- 79,105 ----
  
      1 Full backwards compatibility can be achieved as follows.  When
!       an object defines tp_compare() but not tp_richcompare(), and a
!       rich comparison is requested, the outcome of tp_compare() is
!       used in the ovious way.  E.g. if "<" is requested, an exception if
        tp_compare() raises an exception, the outcome is 1 if
        tp_compare() is negative, and 0 if it is zero or positive.  Etc.
  
!       Full forward compatibility can be achieved as follows.  When a
!       classic comparison is requested on an object that implements
!       tp_richcompare(), up to three comparisons are used: first == is
!       tried, and if it returns true, 0 is returned; next, < is tried
!       and if it returns true, -1 is returned; next, > is tried and if
!       it returns true, +1 is returned.  If any operator tried returns
!       a non-Boolean value (see below), the exception raised by
!       conversion to Boolean is passed through.  If none of the
!       operators tried returns true, the classic comparison fallbacks
!       are tried next.
! 
!       (I thought long and hard about the order in which the three
!       comparisons should be tried.  At one point I had a convincing
!       argument for doing it in this order, based on the behavior of
!       comparisons for cyclical data structures.  But since that code
!       has changed again, I'm not so sure that it makes a difference
!       any more.)
  
      2 Any type that returns a collection of Booleans instead of a
***************
*** 117,123 ****
        (A<B)&(C<D).
  
!     6 The min(), max() and list.sort() operations will only use the
!       < operator.  The 'in' and 'not in' operators and dictionary
!       lookup will only use the == operator.
  
  
--- 127,134 ----
        (A<B)&(C<D).
  
!     6 The min() and list.sort() operations will only use the
!       < operator; max() will only use the > operator.  The 'in' and
!       'not in' operators and dictionary lookup will only use the ==
!       operator.
  
  
***************
*** 128,132 ****
      C API
  
!     - New function:
  
        PyObject *PyObject_RichCompare(PyObject *, PyObject *, enum cmp_op)
--- 139,143 ----
      C API
  
!     - New functions:
  
        PyObject *PyObject_RichCompare(PyObject *, PyObject *, enum cmp_op)
***************
*** 134,139 ****
        This performs the requested rich comparison, returning a Python
        object or raising an exception.  The 3rd argument must be one of
!       LT, LE, EQ, NE, GT or GE.
  
      - New typedef:
  
--- 145,159 ----
        This performs the requested rich comparison, returning a Python
        object or raising an exception.  The 3rd argument must be one of
!       Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT or Py_GE.
  
+       int PyObject_RichCompareBool(PyObject *, PyObject *, enum cmp_op)
+ 
+       This performs the requested rich comparison, returning a
+       Boolean: -1 for exception, 0 for false, 1 for true.  The 3rd
+       argument must be one of Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT or
+       Py_GE.  Note that when PyObject_RichCompare() returns a
+       non-Boolean object, PyObject_RichCompareBool() will raise an
+       exception.
+ 
      - New typedef:
  
***************
*** 144,147 ****
--- 164,174 ----
        richcmpfunc tp_richcompare;
  
+       This should be a function with the same signature as
+       PyObject_RichCompare(), and performing the same comparison.
+       At least one of the arguments is of the type whose
+       tp_richcompare slot is being used, but the other may have a
+       different type.  If the function cannot compare the particular
+       combination of objects, it should return PyExc_NotImplemented.
+ 
      - PyObject_Compare() is changed to try rich comparisons if they
        are defined (but only if classic comparisons aren't defined).
***************
*** 152,219 ****
        the outcome of a particular comparison (e.g. in list.sort(), and
        of course for the comparison operators in ceval.c), the code is
!       changed to call PyObject_RichCompare() instead; if the C code
!       needs to know the outcome of the comparison, PyObject_IsTrue()
!       is called on the result (which may raise an exception).
  
!     - All built-in types that currently define a comparison will be
        modified to define a rich comparison instead.  (This is
!       optional!)
  
      Classes
- 
-     - Classes can define new special methods __lt__, __le__, __gt__,
-       __ge__, __eq__, __ne__ to override the corresponding operators.
-       (You gotta love the Fortran heritage.)  If a class overrides
-       __cmp__ as well, it is only used by PyObject_Compare().
- 
- 
- Unresolved Issues
- 
-     - David Ascher's proposal also introduces cmp(a, b, op) where op
-       is one of "<", "<=", ">", ">=", "==", "!=", which should return
-       the same as a <op> b.  Is this necessary?
- 
-     - The rules for mixed comparisons are confusing.  I propose to
-       wait until the new coercion mechanism is in place, and use the
-       new coercion rules for mixed comparisons.  This may occasionally
-       cause x<y to be replaced by y>x, if x doesn't implement
-       comparison to y, but y does implement comparison to x.
- 
-     - With the above design, if a type or class defines both classic
-       and rich comparisons, classic comparisons override rich
-       comparisons when PyObject_Compare() is called, but rich
-       comparisons override when PyObject_RichCompare() is called.  Is
-       this right?  Or should rich comparisons always win except when
-       cmp() is called?
- 
-     - Should we even bother upgrading the existing types?
- 
-     - If so, how should comparisons on container types be defined?
-       Suppose we have a list whose items define rich comparisons.  How
-       should the itemwise comparisons be done?  For example:
- 
-         def __lt__(a, b): # a<b for lists
-             for i in range(min(len(a), len(b))):
-                 ai, bi = a[i], b[i]
-                 if ai < bi: return 1
-                 if ai == bi: continue
-                 if ai > bi: return 0
-                 raise TypeError, "incomparable item types"
-             return len(a) < len(b)
- 
-       This uses the same sequence of comparisons as cmp(), so it may
-       as well use cmp() instead:
- 
-         def __lt__(a, b): # a<b for lists
-             for i in range(min(len(a), len(b))):
-                 c = cmp(a[i], b[i])
-                 if c < 0: return 1
-                 if c == 0: continue
-                 if c > 0: return 0
-                 assert 0 # unreachable
-             return len(a) < len(b)
  
!       And now there's not really a reason to change lists to rich
!       comparisons.
  
  
--- 179,199 ----
        the outcome of a particular comparison (e.g. in list.sort(), and
        of course for the comparison operators in ceval.c), the code is
!       changed to call PyObject_RichCompare() or
!       PyObject_RichCompareBool() instead; if the C code needs to know
!       the outcome of the comparison, PyObject_IsTrue() is called on
!       the result (which may raise an exception).
  
!     - Most built-in types that currently define a comparison will be
        modified to define a rich comparison instead.  (This is
!       optional; I've converted lists, tuples, complex numbers, and
!       arrays so far, and am not sure whether I will convert others.)
  
      Classes
  
!     - Classes can define new special methods __lt__, __le__, __eq__,
!       __ne__,__gt__, __ge__ to override the corresponding operators.
!       (I.e., <, <=, ==, !=, >, >=. You gotta love the Fortran
!       heritage.)  If a class defines __cmp__ as well, it is only used
!       when __lt__ etc. have been tried and return NotImplemented.