Author ethan.furman
Recipients ethan.furman, gvanrossum, josh.r, serhiy.storchaka, steven.daprano, terry.reedy, veky, xtreak
Date 2020-03-11.20:49:03
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1583959743.33.0.0233307253173.issue35712@roundup.psfhosted.org>
In-reply-to
Content
Serhiy:
------
> First, it is impossible. nb_bool and PyObject_IsTrue() can return
> only three value: 1 for true, 0 for false, and -1 for error.

Huh.  How is -1 interpreted?  Does it become a TypeError?


> It is not possible to represent NotImplemented without breaking all
> extensions.
> 
> Currently
> 
>     if not a:
>         b()
>     else:
>         c()
> 
> is equivalent to
> 
>    if a:
>        c()
>     else:
>         b()
> 
> If a is NotImplemented, what branch be executed in every case?

Side-stepping to other __dunder__ methods for a moment: if, for example, both __add__ and __radd__ return NotImplemented then the interpreter will convert that into a TypeError.

So my thinking is that when the interpreter gets the `NotImplemented` returned by either `if a` or by `if not a` that it would be converted to a `TypeError`, meaning none of the branches would be executed as an exception would be raised instead.

> Second, it would not help. Because real-world examples are not always so
> trivial as "return not self.__lt__(other)". It may be a part of more
> complex expression, e.g.:
> 
>     return super().__eq__(other) and self.attr == other.attr

I don't see the problem -- breaking it down:

    return super().__eq__(other) and self.attr == other.attr

becomes

    return NotImplemented and ...

and the `and` machinery sees it has a `NotImplemented` and raises a `TypeError`.  The same would be true if the `__eq__` operation returned `NotImplemented`.

So to make that work, `and` and `or` would have to check if one of the operands is `NotImplemented`.  Are there others that would need to have that check?

The reason I would prefer this solution is that if it could behave as I described above, the `TypeError` would point at the user's line of code as being the problem, and not inside the __dunder__:

    class NoAdd:
        #
        def __add__(self, other):
            return NotImplemented
        #
        def __radd__(self, other):
            # fake a NotImplemented TypeError from bool(NotImplemented)
            raise TypeError("cannot boolean NotImplemented")

    # what we should see, since the error is in the users' code
    --> NoAdd() + 7
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unsupported operand type(s) for +: 'NoAdd' and 'int'

    # what we will see -- a leaky implementation detail
    --> 7 + NoAdd()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 6, in __radd__
    TypeError: cannot boolean NotImplemented
History
Date User Action Args
2020-03-11 20:49:03ethan.furmansetrecipients: + ethan.furman, gvanrossum, terry.reedy, steven.daprano, serhiy.storchaka, josh.r, veky, xtreak
2020-03-11 20:49:03ethan.furmansetmessageid: <1583959743.33.0.0233307253173.issue35712@roundup.psfhosted.org>
2020-03-11 20:49:03ethan.furmanlinkissue35712 messages
2020-03-11 20:49:03ethan.furmancreate