epiphany

Steven D'Aprano steve+comp.lang.python at pearwood.info
Thu Apr 25 00:32:27 EDT 2013


On Wed, 24 Apr 2013 19:25:37 -0700, Ethan Furman wrote:

> On 04/24/2013 06:35 PM, Steven D'Aprano wrote:
>> Objects are supposed to return NotImplemented from special dunder
>> methods like __add__, __lt__, etc. to say "I don't know how to
>> implement this method for the given argument". Python will then try
>> calling the other object's special method. If both objects return
>> NotImplemented, Python falls back on whatever default behaviour is
>> appropriate.
>>
>> So, knowing nothing of your application, I fear that this is an abuse
>> of NotImplemented's semantics. If a rule returns NotImplemented, I
>> would expect your application to fall back on a different rule. If
>> that's not the case, you're using it in a non-standard way that will
>> cause confusion for those with expectations of what NotImplemented
>> means.
> 
> Why would you assume some random application is going to deal with
> NotImplemented the same way the python interpreter does?


Why would you assume that some random application is going to treat x==y 
the same way the Python interpreter does?

Just because you can design your objects to do anything you want doesn't 
mean you should. Breaking conventions carries costs by the mere fact that 
you're breaking conventions. There are established semantics that an 
experienced Python developer will expect for NotImplemented, and doing 
something else risks causing confusion and mistakes.

Or worse, bugs. If there is any chance that a rule might be called in a 
context where the Python interpreter gets to interpret the return result 
before you see it, then returning NotImplemented could lead to difficult 
to debug problems.



> And even the
> interpreter isn't consistent -- sometimes it will return false (__eq__)
> and sometimes it will raise an Exception (__add__).

As I said:

"If both objects return NotImplemented, Python falls back on whatever 
default behaviour is appropriate."

If neither object knows how to compare the other for equality, the 
appropriate behaviour is to treat them as unequal. If neither object 
knows how to add itself to the other, the appropriate behaviour is to 
raise an exception.


> I hardly think it an abuse of NotImplemented to signal something is not
> implemented when NotImplemented means, um, not implemented.

It doesn't just mean "not implemented in general", it has a specific 
meaning: "I don't know what to do here, let the other object handle it".

As I have repeatedly said, I don't know the context of the application, 
but from what little has been described, this part of it doesn't feel to 
me like a good, clean design. I might be wrong, but from the outside it 
feels like the API should be that rules return a three-state logic 
instance:

True, False, Unknown

where Unknown can be trivially created with 

Unknown = object()

The semantics of NotImplementedError is that it is an *error*, and that 
doesn't sound appropriate given the example shown. Why would a rule that 
raises an *error* exception be treated as if it had passed? That's just 
wrong.

The semantics of NotImplemented is that it is a signal for one object to 
say "I don't know how to do this, let somebody else try". That also 
doesn't seem appropriate. There's no sign that Roy's application does the 
equivalent to this:

result = rule()
if result is NotImplemented:
    result = another_rule()
if result is NotImplemented:
    result = some_default


Since rules apparently take no arguments, either:

1) they rely on global state, which is a nasty design; or

2) rules actually have a fixed return result, in which case why make them 
functions in the first place?


Since both possibilities seem stupid, and I do not believe that Roy 
actually is stupid, I suspect that his example over-simplifies the 
situation. But I can't comment on the infinite number of things that his 
code might do, I can only comment on the examples as actually given, and 
as given, I don't think that either NotImplementedError or NotImplemented 
is a clean solution to the problem.


-- 
Steven



More information about the Python-list mailing list