-
Notifications
You must be signed in to change notification settings - Fork 274
Description
In astral-sh/ruff#20284, we reworked our logic so that Hashable is treated equivalently to object in subtyping and assignability checks. This is defensible from a theoretical perspective, since all instances of "exactly object" are hashable at runtime, which therefore makes object a subtype of Hashable by all normal rules of protocol assignability and subtyping. However, rules around hashability in Python do not obey the normal rules: hashable classes often inherit from unhashable ones, and unhashable classes often inherit from hashable ones, flying in the face of the Liskov Substitution Principle. Our current approach to Hashable and similar protocols makes these protocols effectively useless; we will not complain about code like this, even though users would expect us to do so (and even though other type checkers issue complaints):
from typing import Hashable
def f(x: Hashable): ...
f([])Given that the Liskov principle is so frequently and fragrantly violated for hashability, in Python's builtin types, standard library, and across a wide range of Python code, it may be worth us seeing if we can roll back astral-sh/ruff#20284 and find another solution to #1132 that improves our compatibility with other type checkers. The reason why other type checkers do not run into problems such as #1132 is that they do not eagerly simplify unions of Hashable and other types in the same way we do. We should consider doing the same; it would probably lead to more intuitive behaviour from users' perspective, and compatibility with other type checkers is also a useful goal.