From 92cf95f45b53a6d42c45014fbe5ff3137d1cf2df Mon Sep 17 00:00:00 2001
From: Guido van Rossum <guido@python.org>
Date: Mon, 3 Jun 2002 19:06:41 +0000
Subject: Addressed SF bug 421973 (finally).

Rewrote the subsection on coercion rules (and made it a proper
subsection, with a label).  The new section is much less precise,
because precise rules would be too hard to give (== I don't know what
they are any more :-).  OTOH, the new section gives much more
up-to-date information.

Also noted that __coerce__ may return NotImplemented, with the same
meaning as None.

I beg Fred forgiveness: my use of \code{} is probably naive.  Please
fix this and other markup nits.  An index entry would be nice.

This could be a 2.2 bugfix candidate, if we bother about old docs
(Fred?)
---
 Doc/ref/ref3.tex | 134 ++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 88 insertions(+), 46 deletions(-)

diff --git a/Doc/ref/ref3.tex b/Doc/ref/ref3.tex
index f1fecf0..c06e54d 100644
--- a/Doc/ref/ref3.tex
+++ b/Doc/ref/ref3.tex
@@ -1511,74 +1511,116 @@ the common type would be the type of \code{other}, it is sufficient to
 return \code{None}, since the interpreter will also ask the other
 object to attempt a coercion (but sometimes, if the implementation of
 the other type cannot be changed, it is useful to do the conversion to
-the other type here).
+the other type here).  A return value of \code{NotImplemented} is
+equivalent to returning \code{None}.
 \end{methoddesc}
 
-\strong{Coercion rules}: to evaluate \var{x} \var{op} \var{y}, the
-following steps are taken (where \method{__\var{op}__()} and
-\method{__r\var{op}__()} are the method names corresponding to
-\var{op}, e.g., if \var{op} is `\code{+}', \method{__add__()} and
-\method{__radd__()} are used).  If an exception occurs at any point,
-the evaluation is abandoned and exception handling takes over.
+\subsection{Coercion rules\label{coercion-rules}}
+
+This section used to document the rules for coercion.  As the language
+has evolved, the coercion rules have become hard to document
+precisely; documenting what one version of one particular
+implementation does is undesirable.  Instead, here are some informal
+guidelines regarding coercion.  In Python 3.0, coercion will not be
+supported.
 
 \begin{itemize}
 
-\item[0.] If \var{x} is a string object and \var{op} is the modulo
-        operator (\%), the string formatting operation is invoked and
-        the remaining steps are skipped.
+\item
+
+If the left operand of a \% operator is a string or Unicode object, no
+coercion takes place and the string formatting operation is invoked
+instead.
+
+\item
+
+It is no longer recommended to define a coercion operation.
+Mixed-mode operations on types that don't define coercion pass the
+original arguments to the operation.
+
+\item
+
+New-style classes (those derived from \code{object}) never invoke the
+\code{__coerce__} method in response to a binary operator; the only
+time \code{__coerce__} is invoked is when the built-in function
+\code{coerce()} is called.
+
+\item
+
+For most intents and purposes, an operator that returns
+\code{NotImplemented} is treated the same as one that is not
+implemented at all.
 
-\item[1.] If \var{x} is a class instance:
+\item
 
-        \begin{itemize}
+Below, \method{__op__()} and \method{__rop__()} are used to signify
+the generic method names corresponding to an operator;
+\method{__iop__} is used for the corresponding in-place operator.  For
+example, for the operator `\code{+}', \method{__add__()} and
+\method{__radd__()} are used for the left and right variant of the
+binary operator, and \method{__iadd__} for the in-place variant.
 
-        \item[1a.] If \var{x} has a \method{__coerce__()} method:
-        replace \var{x} and \var{y} with the 2-tuple returned by
-        \code{\var{x}.__coerce__(\var{y})}; skip to step 2 if the
-        coercion returns \code{None}.
+\item
 
-        \item[1b.] If neither \var{x} nor \var{y} is a class instance
-        after coercion, go to step 3.
+For objects \var{x} and \var{y}, first \code{\var{x}.__op__(\var{y})}
+is tried.  If this is not implemented or returns \code{NotImplemented},
+\code{\var{y}.__rop__(\var{x})} is tried.  If this is also not
+implemented or returns \code{NotImplemented}, a \code{TypeError}
+exception is raised.  But see the following exception:
 
-        \item[1c.] If \var{x} has a method \method{__\var{op}__()}, return
-        \code{\var{x}.__\var{op}__(\var{y})}; otherwise, restore \var{x} and
-        \var{y} to their value before step 1a.
+\item
 
-        \end{itemize}
+Exception to the previous item: if the left operand is an instance of
+a built-in type or a new-style class, and the right operand is an
+instance of a proper subclass of that type or class, the right
+operand's \code{__rop__} method is tried \emph{before} the left
+operand's \code{__op__} method.  This is done so that a subclass can
+completely override binary operators.  Otherwise, the left operand's
+__op__ method would always accept the right operand: when an instance
+of a given class is expected, an instance of a subclass of that class
+is always acceptable.
 
-\item[2.] If \var{y} is a class instance:
+\item
 
-        \begin{itemize}
+When either operand type defines a coercion, this coercion is called
+before that type's \code{__op__} or \code{__rop__} method is called,
+but no sooner.  If the coercion returns an object of a different type
+for the operand whose coercion is invoked, part of the process is
+redone using the new object.
 
-        \item[2a.] If \var{y} has a \method{__coerce__()} method:
-        replace \var{y} and \var{x} with the 2-tuple returned by
-        \code{\var{y}.__coerce__(\var{x})}; skip to step 3 if the
-        coercion returns \code{None}.
+\item
 
-        \item[2b.] If neither \var{x} nor \var{y} is a class instance
-        after coercion, go to step 3.
+When an in-place operator (like `\code{+=}') is used, if the left
+operand implements \code{__iop__}, it is invoked without any coercion.
+When the operation falls back to \code{__op__} and/or \code{__rop__},
+the normal coercion rules apply.
 
-        \item[2b.] If \var{y} has a method \method{__r\var{op}__()},
-        return \code{\var{y}.__r\var{op}__(\var{x})}; otherwise,
-        restore \var{x} and \var{y} to their value before step 2a.
+\item
 
-        \end{itemize}
+In \var{x}\code{+}\var{y}, if \var{x} is a sequence that implements
+sequence concatenation, sequence concatenation is invoked.
 
-\item[3.] We only get here if neither \var{x} nor \var{y} is a class
-instance.
+\item
 
-        \begin{itemize}
+In \var{x}\code{*}\var{y}, if one operator is a sequence that
+implements sequence repetition, and the other is an integer
+(\code{int} or \code{long}), sequence repetition is invoked.
 
-        \item[3a.] If \var{op} is `\code{+}' and \var{x} is a
-        sequence, sequence concatenation is invoked.
+\item
 
-        \item[3b.] If \var{op} is `\code{*}' and one operand is a
-        sequence and the other an integer, sequence repetition is
-        invoked.
+Rich comparisons (implemented by methods \code{__eq__} and so on)
+never use coercion.  Three-way comparison (implemented by
+\code{__cmp__}) does use coercion under the same conditions as
+other binary operations use it.
 
-        \item[3c.] Otherwise, both operands must be numbers; they are
-        coerced to a common type if possible, and the numeric
-        operation is invoked for that type.
+\item
 
-        \end{itemize}
+In the current implementation, the built-in numeric types \code{int},
+\code{long} and \code{float} do not use coercion; the type
+\code{complex} however does use it.  The difference can become
+apparent when subclassing these types.  Over time, the type
+\code{complex} may be fixed to avoid coercion.  All these types
+implement a \code{__coerce__} method, for use by the built-in
+\code{coerce} function.
 
 \end{itemize}
-- 
cgit v0.12

