No, the reason is that if we did this with exceptions, it would be liable to mask errors; an exception does not necessarily originate immediately with the code you invoked, it could have been raised by something else that was invoked by that code. The special value NotImplemented must pretty much originate directly in the invoked code, since the implementation guarantees that e.g. a+b can never *return* NotImplemented: if a.__add__(b) and b.__radd__(a) both return NotImplemented, TypeError is raised.
That makes sense - although for that reasoning, a TypeError subclass that the binary operation machinery promotes to a standard TypeError would seem to work too (with the advantage of also raising at least some sort of exception when the method is called directly)
You went on to great lengths later about how it's less natural in Python to return an error value, but I disagree. I've written a lot of code like this and it's quite natural to write things like this:
def __add__(self, other): if not isinstance(other, ThisClass): return NotImplemented return ...implementation of self + other...
It wasn't so much this part that struck me as ugly, as the subsequent usage of the methods directly in the Decimal Context implementation.
The inconsistency of the interface was the main irritation. All of the methods that implemented standard binary operations returned NotImplemented on an argument error, while other methods raised TypeError directly. So for some methods Context was checking the return value and raising TypeError, but for others it was just making the call. The mixture of the two styles didn't look nice :)
If you want to factor out the type check, it makes just as much sense to define a Boolean function:
def __add__(self, other): if not self.acceptableArgument(other): return NotImplemented ...etc...
I'm considering an approach that involves the simple wrapper function:
def raiseIfNotImplemented(func, message): def wrapper(*args, **kwds): result = func(*args, **kwds) if result is NotImplemented: raise TypeError(message) return result
After rewriting _convert_other and all the binary special methods to return NotImplemented for bad arguments (as you suggest), the wrapper above can be used to provide alternate functions that raise the TypeError instead (making it easy to provide a consistent API for use by Context).
Obviously, such a strategy makes this a 2.5 only solution, as it involves adding methods. A potentially-2.4-compatible solution is the one I used in 'friendly decimal' which simply duplicates the code of the above wrapper wherever it is needed by Decimal or Context.
I'm guessing this wasn't caught before 2.4 was released because most people reviewing the code were more interested in correct computations than into correct integration in the Python framework.
This is quite likely to be true :)
Although I find it interesting that string objects share the same characteristic of not respecting __rop__ when it is provided by another class that is not a subclass of string.
Regards, Nick.
-- Nick Coghlan | [EMAIL PROTECTED] | Brisbane, Australia --------------------------------------------------------------- http://boredomandlaziness.skystorm.net _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com