Deprecate/change the behaviour of ~bool

Currently ~False is -1 and ~True is -2. Would be nicer if ~bool was the same as not bool. Hopefully nobody actually relies on this but nevertheless, it would be a backwards-incompatible change so the whole deprecation warnings and whatnot would be required. In particular, this is nice for xnor operator: a ^~ b. This currently works on ints, but not on bools, while most other operators, including xor, do successfully work on bools.

On Tue, Feb 23, 2021 at 12:14 PM Soni L. <fakedme+py@gmail.com> wrote:
There are quite a few ways in which bitwise operators are not the same as boolean operators. What would be the advantage of having them be the same in just this one case?
You could write it as a ^ (not b), as long as you don't mind it giving back an integer rather than a bool. Fundamentally, you're doing bitwise operations on integers, and expecting them to behave as if they have only a single bit each, so another way to resolve this might be to mask it off at the end with "& 1". If this makes your code horrendously ugly, perhaps it would be better to create your own "one-bit integer" class, which responds to all bitwise operators by automatically masking down to one bit? ChrisA

You could write it as a ^ (not b), as long as you don't mind it giving back an integer rather than a bool.
Actually, that'll give back a bool if a is a bool (and (not b) produces a bool); ^ is overridden for bool/bool operations and itself returns a bool. On Tue, Feb 23, 2021 at 1:48 AM Chris Angelico <rosuav@gmail.com> wrote:

On Tue, 23 Feb 2021 at 02:13, Soni L. <fakedme+py@gmail.com> wrote:
Currently ~False is -1 and ~True is -2. Would be nicer if ~bool was the same as not bool.
I suspect this is more for NumPy people. I remember that one of my bosses used `~a` on a bool because he started with NumPy and had a limited knowledge of Python.

On Mon, Feb 22, 2021 at 10:11:14PM -0300, Soni L. wrote:
Currently ~False is -1 and ~True is -2. Would be nicer if ~bool was the same as not bool.
That's your opinion. I disagree. Bitwise-not is not the same thing as boolean-not, and they should not be spelled the same, especially not when that would break the invariant that if `a == b` then `~a == ~b`.
If you want boolean-not, then use the boolean-not operator `not`.
In particular, this is nice for xnor operator: a ^~ b. This currently works on ints, but not on bools
If it works on ints, of course it works on bools, because bools are ints. You get identical results whether you use int (0, 1) or bools (False, True) in every combination:
-- Steve

64-bit bools were a mistake, tbh. Oh well, at least we tried. What about getting the parser to recognize ^~ as an XNOR operator and have __xnor__ on bools actually do xnor on bools? Make xnor a real operator by fusing two operators together! On 2021-02-23 5:49 a.m., Steven D'Aprano wrote:

On Tue, Feb 23, 2021 at 01:57:08PM -0300, Soni L. wrote:
64-bit bools were a mistake, tbh. Oh well, at least we tried.
What language are you talking about? In Python, bool is a subclass of int, which is a BigNum, not 64 bits.
Let's not break existing code for the sake of an operator that hardly anyone ever uses. There are exactly 2**4 = 16 boolean operators of two variables. Python only supports two: `and` and `or`. Plus a single unary operator `not` (out of four possible unary operators). What makes xnor so special that you want it to be an operator? Do you have any use-cases for an xnor operator? What do you use it for? These are not rhetorical questions. If you want to push this proposal forward, you need to start with actual concrete use-cases, not "it would be nice ..." and "how about ...". Why can't you write a function to do what you want? -- Steve

On 2021-02-23 7:10 p.m., Steven D'Aprano wrote:
It's because someone was doing a comparison of a bool to the result of a comparison, a la (x == y) == z, and that looks kinda weird (especially because x == y == z has a completely different meaning). ^ works as a replacement for != but for == the only option is to either use "thing ^ (not foo)" or "not (thing ^ foo)". It's not that it's special - we "technically" already have it, if you abuse another language feature - it'd just make some code easier to understand.

I don't think we want to add a new dunder just to make it easier for people to abuse bitwise operators instead of using the `!=` operator. -- Steve

Python implements more then 2 of them: True False not and or https://en.wikipedia.org/wiki/Boolean_algebras_canonically_defined#Truth_tab... Barry

On Thu, Feb 25, 2021 at 4:28 AM Barry Scott <barry@barrys-emacs.org> wrote:
True and False aren't operators in Python. Notionally you could say that "take any input(s) and return True" could be considered an operator in theory, but you can't write "x True y" to achieve that in Python. ChrisA

On 2/24/21 12:34 PM, Chris Angelico wrote:
True, but you aren't really going to define real operators in a language that always ignore one or both of their arguments. Thus, of the 16 theoretical operators in the list, the 6 that don't depend on both values aren't going to get a real operator, and if you actually want that operation, you do have a 'spelling' in Python for it. -- Richard Damon

On 2/24/21 12:26 PM, Barry Scott wrote:
Of the unary, python implements them all, the possible opererators for op a are: True False a not a Of the 16 binary operators a op b you can get: * True * False * a * b * not a * not b * a and b * a or b and for things that are already bools, you can use * a < b * a <= b * a == b * a != b * a > b * a >= b The only combinations you can't get with a simple operator are 'not (a and b)' and 'not (a or b)' (nand and nor) assuming you are starting with true bools (or 0 and 1). If you only have 'truthy' values, you only get 1/2 of the possible options. -- Richard Damon

On Wed, Feb 24, 2021 at 12:51:24PM -0500, Richard Damon wrote:
Those who have read my posts over the years will realise that I enjoy being pedantic as much as the next guy, but the trick to being pedantic is that you have to be *correct* in your pedantry :-) The only operator in your list is `not`. True and False are values, not operators: you can't say "True x" to ignore the value of x and return True. And likewise `a` has no operator at all. I'm sure that philosophers would like to debate whether the absense of an operator counts as an operator, but from the point of view of a programmer, it's hard to google for an operator that isn't there :-) Of course, as you pointed out in another post, it's unlikely for any practical programming language to define such operators, although that's the sort of thing that esoteric languages might do. For the record, here are the four unary operators defined as functions: def contradiction(a): return False def tautology(a): return True def identity(a): return a def negation(a): return not a
Of the 16 binary operators a op b you can get: [...]
There is no question that we can get the results of calling all sixteen boolean operators, but whether Python defines them or not. Although I'll grant you that using the comparison operators is a very nice trick, e.g. using `==` to spell the "material biconditional" operator. I totally forgot that you could do that, so thank you. I guess Python does define more than `and` and `or` after all :-) Speaking of esoteric languages, one can define the complete set of boolean 1- and 2-argument operators using only two functions, plus a third helper to display the results: def true(x, y): return x def false(x, y): return y def print_bool(b): print b("true", "false") print_bool(true) print_bool(false) Using just those two functions, we can define all boolean operators. def And(a, b): return a(b, a) def Or(a, b): return a(a, b) The others are left as an exercise :-) -- Steve

On Tue, Feb 23, 2021 at 12:14 PM Soni L. <fakedme+py@gmail.com> wrote:
There are quite a few ways in which bitwise operators are not the same as boolean operators. What would be the advantage of having them be the same in just this one case?
You could write it as a ^ (not b), as long as you don't mind it giving back an integer rather than a bool. Fundamentally, you're doing bitwise operations on integers, and expecting them to behave as if they have only a single bit each, so another way to resolve this might be to mask it off at the end with "& 1". If this makes your code horrendously ugly, perhaps it would be better to create your own "one-bit integer" class, which responds to all bitwise operators by automatically masking down to one bit? ChrisA

You could write it as a ^ (not b), as long as you don't mind it giving back an integer rather than a bool.
Actually, that'll give back a bool if a is a bool (and (not b) produces a bool); ^ is overridden for bool/bool operations and itself returns a bool. On Tue, Feb 23, 2021 at 1:48 AM Chris Angelico <rosuav@gmail.com> wrote:

On Tue, 23 Feb 2021 at 02:13, Soni L. <fakedme+py@gmail.com> wrote:
Currently ~False is -1 and ~True is -2. Would be nicer if ~bool was the same as not bool.
I suspect this is more for NumPy people. I remember that one of my bosses used `~a` on a bool because he started with NumPy and had a limited knowledge of Python.

On Mon, Feb 22, 2021 at 10:11:14PM -0300, Soni L. wrote:
Currently ~False is -1 and ~True is -2. Would be nicer if ~bool was the same as not bool.
That's your opinion. I disagree. Bitwise-not is not the same thing as boolean-not, and they should not be spelled the same, especially not when that would break the invariant that if `a == b` then `~a == ~b`.
If you want boolean-not, then use the boolean-not operator `not`.
In particular, this is nice for xnor operator: a ^~ b. This currently works on ints, but not on bools
If it works on ints, of course it works on bools, because bools are ints. You get identical results whether you use int (0, 1) or bools (False, True) in every combination:
-- Steve

64-bit bools were a mistake, tbh. Oh well, at least we tried. What about getting the parser to recognize ^~ as an XNOR operator and have __xnor__ on bools actually do xnor on bools? Make xnor a real operator by fusing two operators together! On 2021-02-23 5:49 a.m., Steven D'Aprano wrote:

On Tue, Feb 23, 2021 at 01:57:08PM -0300, Soni L. wrote:
64-bit bools were a mistake, tbh. Oh well, at least we tried.
What language are you talking about? In Python, bool is a subclass of int, which is a BigNum, not 64 bits.
Let's not break existing code for the sake of an operator that hardly anyone ever uses. There are exactly 2**4 = 16 boolean operators of two variables. Python only supports two: `and` and `or`. Plus a single unary operator `not` (out of four possible unary operators). What makes xnor so special that you want it to be an operator? Do you have any use-cases for an xnor operator? What do you use it for? These are not rhetorical questions. If you want to push this proposal forward, you need to start with actual concrete use-cases, not "it would be nice ..." and "how about ...". Why can't you write a function to do what you want? -- Steve

On 2021-02-23 7:10 p.m., Steven D'Aprano wrote:
It's because someone was doing a comparison of a bool to the result of a comparison, a la (x == y) == z, and that looks kinda weird (especially because x == y == z has a completely different meaning). ^ works as a replacement for != but for == the only option is to either use "thing ^ (not foo)" or "not (thing ^ foo)". It's not that it's special - we "technically" already have it, if you abuse another language feature - it'd just make some code easier to understand.

I don't think we want to add a new dunder just to make it easier for people to abuse bitwise operators instead of using the `!=` operator. -- Steve

Python implements more then 2 of them: True False not and or https://en.wikipedia.org/wiki/Boolean_algebras_canonically_defined#Truth_tab... Barry

On Thu, Feb 25, 2021 at 4:28 AM Barry Scott <barry@barrys-emacs.org> wrote:
True and False aren't operators in Python. Notionally you could say that "take any input(s) and return True" could be considered an operator in theory, but you can't write "x True y" to achieve that in Python. ChrisA

On 2/24/21 12:34 PM, Chris Angelico wrote:
True, but you aren't really going to define real operators in a language that always ignore one or both of their arguments. Thus, of the 16 theoretical operators in the list, the 6 that don't depend on both values aren't going to get a real operator, and if you actually want that operation, you do have a 'spelling' in Python for it. -- Richard Damon

On Thu, Feb 25, 2021 at 5:05 AM Richard Damon <Richard@damon-family.org> wrote:
Sure. In any case, since it's easy to define operators in terms of each other, Python needs just a handful to give the power to the programmer. The others don't need any language support. ChrisA

On 2/24/21 12:26 PM, Barry Scott wrote:
Of the unary, python implements them all, the possible opererators for op a are: True False a not a Of the 16 binary operators a op b you can get: * True * False * a * b * not a * not b * a and b * a or b and for things that are already bools, you can use * a < b * a <= b * a == b * a != b * a > b * a >= b The only combinations you can't get with a simple operator are 'not (a and b)' and 'not (a or b)' (nand and nor) assuming you are starting with true bools (or 0 and 1). If you only have 'truthy' values, you only get 1/2 of the possible options. -- Richard Damon

On Wed, Feb 24, 2021 at 12:51:24PM -0500, Richard Damon wrote:
Those who have read my posts over the years will realise that I enjoy being pedantic as much as the next guy, but the trick to being pedantic is that you have to be *correct* in your pedantry :-) The only operator in your list is `not`. True and False are values, not operators: you can't say "True x" to ignore the value of x and return True. And likewise `a` has no operator at all. I'm sure that philosophers would like to debate whether the absense of an operator counts as an operator, but from the point of view of a programmer, it's hard to google for an operator that isn't there :-) Of course, as you pointed out in another post, it's unlikely for any practical programming language to define such operators, although that's the sort of thing that esoteric languages might do. For the record, here are the four unary operators defined as functions: def contradiction(a): return False def tautology(a): return True def identity(a): return a def negation(a): return not a
Of the 16 binary operators a op b you can get: [...]
There is no question that we can get the results of calling all sixteen boolean operators, but whether Python defines them or not. Although I'll grant you that using the comparison operators is a very nice trick, e.g. using `==` to spell the "material biconditional" operator. I totally forgot that you could do that, so thank you. I guess Python does define more than `and` and `or` after all :-) Speaking of esoteric languages, one can define the complete set of boolean 1- and 2-argument operators using only two functions, plus a third helper to display the results: def true(x, y): return x def false(x, y): return y def print_bool(b): print b("true", "false") print_bool(true) print_bool(false) Using just those two functions, we can define all boolean operators. def And(a, b): return a(b, a) def Or(a, b): return a(a, b) The others are left as an exercise :-) -- Steve
participants (8)
-
Barry Scott
-
Chris Angelico
-
Guido van Rossum
-
Josh Rosenberg
-
Marco Sulla
-
Richard Damon
-
Soni L.
-
Steven D'Aprano