Python semantic: Is it ok to replace not x == y with x != y? (no)
Hi, I implemented more constant folding optimizations in my FAT Python project, but it looks like I made a subtle change in the Python semantic. Replacing "not x == y" with "x != y" changes the behaviour of Python. For example, this optimization breaks test_unittest because unittest.mock._Call implements __eq__() but not __ne__(). Is it expected that "not x.__eq__(y)" can be different than "x.__ne__(y)"? Is it part of the Python semantic? IMHO it's a bug in the unittest.mock module, but it's "acceptable" because "it just works" :-) So FAT Python must not replace "not x == y" with "x != y" to not break the code. Should Python emit a warning when __eq__() is implemented but not __ne__()? Should Python be modified to call "not __eq__()" when __ne__() is not implemented? For me, it can be an annoying and sublte bug, hard to track. Victor
Oh, I sent my email too quickly, I forgot to ask for other operations. Currently, FAT implements the following optimizations: * "not (x == y)" replaced with "x != y" * "not (x != y)" replaced with "x == y" * "not (x < y)" replaced with "x >= y" * "not (x <= y)" replaced with "x > y" * "not (x > y)" replaced with "x <= y" * "not (x >= y)" replaced with "x < y" * "not (x in y)" replaced with "x not in y" * "not (x not in y)" replaced with "x in y" * "not (x is y)" replaced with "x is not y" * "not (x is not y)" replaced with "x is y" I guess that the optimizations on "in" and "is" operators are fine, but optimizations on all other operations must be removed to not break the Python semantic. Python has also some funny objects like math.nan:
math.nan != math.nan True math.nan == math.nan False math.nan < math.nan False math.nan > math.nan False math.nan <= math.nan False math.nan >= math.nan False
math.nan != 1.0 True math.nan == 1.0 False math.nan <= 1.0 False math.nan < 1.0 False math.nan >= 1.0 False math.nan > 1.0 False
So "not(math.nan < 1.0)" is different than "math.nan >= 1.0"... Victor 2015-12-15 14:04 GMT+01:00 Victor Stinner <victor.stinner@gmail.com>:
Hi,
I implemented more constant folding optimizations in my FAT Python project, but it looks like I made a subtle change in the Python semantic.
Replacing "not x == y" with "x != y" changes the behaviour of Python. For example, this optimization breaks test_unittest because unittest.mock._Call implements __eq__() but not __ne__().
Is it expected that "not x.__eq__(y)" can be different than "x.__ne__(y)"? Is it part of the Python semantic?
IMHO it's a bug in the unittest.mock module, but it's "acceptable" because "it just works" :-) So FAT Python must not replace "not x == y" with "x != y" to not break the code.
Should Python emit a warning when __eq__() is implemented but not __ne__()?
Should Python be modified to call "not __eq__()" when __ne__() is not implemented?
For me, it can be an annoying and sublte bug, hard to track.
Victor
On Tue, Dec 15, 2015 at 8:04 AM, Victor Stinner <victor.stinner@gmail.com> wrote:
Is it expected that "not x.__eq__(y)" can be different than "x.__ne__(y)"? Is it part of the Python semantic?
In Numpy, `x != y` returns an array of bools, while `not x == y` creates an array of bools and then tries to convert it to a bool, which fails, because a non-singleton Numpy array is not allowed to be converted to a bool. But in the context of `if`, both `not x == y` and `x != y` will fail.
From the docs, on implementing comparison: https://docs.python.org/3/reference/datamodel.html#object.__ne__ """ By default, __ne__() delegates to __eq__() and inverts the result unless it is NotImplemented. There are no other implied relationships among the comparison operators, for example, the truth of (x<y or x==y) does not imply x<=y. """
On 15 December 2015 at 23:11, Victor Stinner <victor.stinner@gmail.com> wrote:
I guess that the optimizations on "in" and "is" operators are fine, but optimizations on all other operations must be removed to not break the Python semantic.
Right, this is why we have functools.total_ordering as a class decorator to "fill in" the other comparison implementations based on the ones in the class body. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
On 15.12.15 15:04, Victor Stinner wrote:
Should Python emit a warning when __eq__() is implemented but not __ne__()?
No. Actually I had removed a number of redundant (and often incorrect) __ne__ implementations after fixing object.__ne__.
Should Python be modified to call "not __eq__()" when __ne__() is not implemented?
__ne__() always is implemented (inherited from object). Default __ne__ implementation calls __eq__() and negate it's result (if not NotImplemented). But user class can define __ne__ with arbitrary semantic. That is the purpose of adding __ne__.
participants (4)
-
Franklin? Lee
-
Nick Coghlan
-
Serhiy Storchaka
-
Victor Stinner