There’s reasoning behind the LSP, and it’s to avoid questions like the following.
With ~bool throwing an error, in this code, where is the bug?
def f(x: bool):
...
# Perhaps unusual in reality, but
# expressions like g(a == b) do occur.
g(x)
...
def g(x: int):
...
~x
...
f is passing an int as g asks for. (It is passing a bool, which is an int.) g is calling bitwise not on an int. Both of these operations are supposed to be OK.
These functions may actually be in different packages, of course.
I can see a few answers, only one of which attracts me.
f. Functions should not passbools where aints are expected. The best choice for a new language, but a huge change to Python.g. Functions should ensure thatints they don’t control are notbools before they use bitwise not on them. Bitwise not is pretty rare, but this still seems rather annoying.g.gshould have documented thatxmust not be aboolin this case. This leaks implementation details ofgand makes applying~toints that are passed in a breaking API change.f.fshould not callgwith aboolunless it’s checked it doesn’t~it. This is a sufficient burden to put on everyboolpassed as anintargument and every (even non‐breaking) library update that it’s better just to shoveint(x)in there, making this more or less equivalent to 1.- Doesn’t matter – this never comes up in practice. Functions like
gcertainly come up in practice, I’d imagine as a pretty high proportion of all functions using bitwise not, so this doesn’t really rid us of the question. If the potential bug isn’tg’s fault, then it implicitly blames potential futurefs (which it assumes don’t exist). - Both functions are OK, and the bug is in
bool.