Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 10 additions & 46 deletions crates/ruff_linter/src/rules/pylint/rules/eq_without_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ use crate::checkers::ast::Checker;
///
/// ## Why is this bad?
/// A class that implements `__eq__` but not `__hash__` will have its hash
/// method implicitly set to `None`, regardless of if a super class defines
/// `__hash__`. This will cause the class to be unhashable, will in turn
/// cause issues when using the class as a key in a dictionary or a member
/// of a set.
/// method implicitly set to `None`, regardless of if a superclass defines
/// `__hash__`. This will cause the class to be unhashable, which will in turn
/// cause issues when using instances of the class as keys in a dictionary or
/// members of a set.
///
/// ## Example
///
Expand All @@ -46,52 +46,16 @@ use crate::checkers::ast::Checker;
/// return hash(self.name)
/// ```
///
/// This issue is particularly tricky with inheritance. Even if a parent class correctly implements
/// both `__eq__` and `__hash__`, overriding `__eq__` in a child class without also implementing
/// `__hash__` will make the child class unhashable:
/// In general, it is unsound to inherit a `__hash__` implementation from a parent class while
/// overriding the `__eq__` implementation because the two must be kept in sync. However, an easy
/// way to resolve this error in cases where it _is_ sound is to explicitly set `__hash__` to the
/// parent class's implementation:
///
/// ```python
/// class Person:
/// def __init__(self):
/// self.name = "monty"
///
/// def __eq__(self, other):
/// return isinstance(other, Person) and other.name == self.name
///
/// def __hash__(self):
/// return hash(self.name)
///
///
/// class Developer(Person):
/// def __init__(self):
/// super().__init__()
/// self.language = "python"
/// def __init__(self): ...
///
/// def __eq__(self, other):
/// return (
/// super().__eq__(other)
/// and isinstance(other, Developer)
/// and self.language == other.language
/// )
///
///
/// hash(Developer()) # TypeError: unhashable type: 'Developer'
/// ```
///
/// One way to fix this is to retain the implementation of `__hash__` from the parent class:
///
/// ```python
/// class Developer(Person):
/// def __init__(self):
/// super().__init__()
/// self.language = "python"
///
/// def __eq__(self, other):
/// return (
/// super().__eq__(other)
/// and isinstance(other, Developer)
/// and self.language == other.language
/// )
/// def __eq__(self, other): ...
///
/// __hash__ = Person.__hash__
/// ```
Expand Down
Loading