GeezerVison is showing github.com — bool(~True) == True · Issue #82012 · python/cpython
bool(~True) == True #82012Description
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee = None
closed_at = <Date 2019-08-12.20:25:46.266>
created_at = <Date 2019-08-12.10:48:52.558>
labels = ['interpreter-core', 'type-feature', '3.7']
title = 'bool(~True) == True'
updated_at = <Date 2019-08-14.17:45:40.127>
user = 'https://github.com/tomerv'
bugs.python.org fields:
activity = <Date 2019-08-14.17:45:40.127>
actor = 'gvanrossum'
assignee = 'none'
closed = True
closed_date = <Date 2019-08-12.20:25:46.266>
closer = 'rhettinger'
components = ['Interpreter Core']
creation = <Date 2019-08-12.10:48:52.558>
creator = 'tomerv'
dependencies = []
files = []
hgrepos = []
issue_num = 37831
keywords = []
message_count = 24.0
messages = ['349452', '349459', '349461', '349477', '349478', '349480', '349482', '349484', '349487', '349488', '349489', '349493', '349494', '349495', '349508', '349509', '349522', '349628', '349656', '349661', '349707', '349709', '349723', '349724']
nosy_count = 7.0
nosy_names = ['gvanrossum', 'tim.peters', 'rhettinger', 'mark.dickinson', 'serhiy.storchaka', 'eryksun', 'tomerv']
pr_nums = []
priority = 'normal'
resolution = 'duplicate'
stage = 'resolved'
status = 'closed'
superseder = '12447'
type = 'enhancement'
url = 'https://bugs.python.org/issue37831'
versions = ['Python 3.7']
Linked PRs
Activitytomerv commented on Aug 12, 2019 MannequinAuthor More actions Bitwise operators have inconsistent behavior when acting on bool values: (Python 3.7.4)
# "&" works like "and"
>>> True & True
True
>>> True & False
False
>>> False & False
False
# "|" works like "or"
>>> True | True
True
>>> True | False
True
>>> False | False
False
# "~" does not work like "not"!
>>> ~True
-2
>>> ~False
-1
The result of this is the a user might start working with "&" and "|" on bool values (for whatever reason) and it will work as expected. But then, when adding "~" to the mix, things start to break.
The proposal is to make "~" act like "not" on bool values, i.e. ~True will be False; ~False will be True.
I'm not sure if this has any negative impact on existing code. I don't expect any, but you can never know. If there is no objection to this change, I can even try to implement it myself an submit a patch. mdickinson commented on Aug 12, 2019 For instances of int, ~ does bitwise negation (with the usual two's-complement with an infinite number of bits model that Python uses for all bitwise operations on arbitrary-precision integers).
And rightly or wrongly, True and False are instances of int, so it should be possible to use True almost anywhere you'd usually use 1, with no change in behaviour. The proposed change would give us True == 1 but ~True != ~1.
So I think we're stuck with the current behaviour.
Given a time machine, this could arguably be "fixed" by making True equal to -1 rather than 1 ... But absent that time machine, I'd expect some amount of breakage from the proposed change.
It's worth noting that NumPy's bool_ type does do this:
>>> import numpy as np
>>> ~np.bool_(True)
False
>>> ~np.bool_(False)
True
But np.bool_ doesn't have the same "is-a" relationship with integers:
>>> np.bool_.__mro__
(<class 'numpy.bool_'>, <class 'numpy.generic'>, <class 'object'>)
IOW, -1 from me. mdickinson commented on Aug 12, 2019 Looks like this is essentially a duplicate of bpo-12447 rhettinger commented on Aug 12, 2019 +0 This proposal may be worth re-considering. I've seen the problem arise in practice on multiple occasions. I suspect that it will continue to give people trouble.
Right now, a bool is-a int that 1) only has two singleton instances equal to zero and one, 2) has a different repr, and 3) has the & | and ^ operations redefined to return instances of bool.
I think we could also override the ~ operation. That would be a Liskov violation, making bools slightly less substitutable for ints, but it does so in a way that is intuitive and likely to match what a user intends when inverting a bool. mdickinson commented on Aug 12, 2019 serhiy-storchaka commented on Aug 12, 2019 -1 from me too.
Making True == -1 looks interesting, but it has drawbacks. mdickinson commented on Aug 12, 2019
Making True == -1 looks interesting, but it has drawbacks.
Yes, please ignore that part of my post. :-) It shouldn't be considered seriously until a time machine turns up (and probably not even then).
My main worry with the proposed change is accidental breakage from the change in meaning. I've so far failed to find any examples of real-world functions that could/would be broken - the closest I've come is floating-point bit-pattern manipulation functions (constructing a bit-string from a sign, exponent and significand, where it's quite natural to treat the sign both as an "is_negative" boolean and as a 0-or-1 integer). But that case didn't involve a ~sign at any point, so it doesn't count.
Still, I have a nagging suspicion that such a function will turn up if we make this change.
Having ~True *not* be the same as ~1 feels like a bigger surprise to me than having ~True not be False; it breaks my simple mental model that bools always behave like ints in numeric contexts. mdickinson commented on Aug 12, 2019 There's also the minor annoyance that there isn't currently an obvious safe way to convert an integer-like thing to an actual int, to make sure that bools do the right thing in a numeric context. operator.index *ought* to be that obvious way, but it leaves bools untouched.
>>> operator.index(True)
True tim-one commented on Aug 12, 2019 Mark, isn't int() the obvious way "to convert an integer-like thing to an actual int"?
>>> int(True)
1
>>> int(False)
0
For the rest, I'm -True on making ~ do something magical for bools inconsistent with what it does for ints. "is-a" is a promise. Reacted by Doug Hoskisson serhiy-storchaka commented on Aug 12, 2019 iritkatriel commented on Apr 4, 2023 @timhoffm The deadline for getting this into 3.12 is in about a month. timhoffm commented on Apr 8, 2023 Thanks for the reminder. I may get around this next week. timhoffm commented on Apr 28, 2023 pochmann3 commented on Apr 4, 2024
I don't think I understand why anyone would want to use | and & on bools to get another bool, instead of just using or and and.
I think I've had cases where I wanted a bool and needed both operands evaluated, so or and and wouldn't have worked. terryjreedy commented on Aug 29, 2024
MetadataMetadataDevelopmentNo branches or pull requestsIssue actions
|