The Dilemma
# current annotation in typeshedclassobject:
def__eq__(self, value: object, /) ->bool: ...
This is too strict, because everything subclasses object and some classes may to wish to:
- Narrow the range of allowed objects.
- Use a return type other than
bool (e.g. numpy array element-wise comparison, symbolic computation, etc.)
On the other hand, many APIs (incorrectly) assume that a == b always return a bool, so changing the return type away from bool can lead to problems.
Solving the Dilemma
Satisfying (1) is easy enough by changing value: object to value: Any. (one could maybe explore using Never also)
Satisfying (2) can be achieved in several ways, specifically I tested: (a) -> object, (b) -> Any and (c) -> Any | bool
In particular, for (c) the primer actually looks really good. We have ~50 fixed Unused "type: ignore" comment errors, and 16 suprious [override] errors eliminated, without any new errors.
References
Appendix: How python's a==b works internally
This cannot be properly annotated with the current type system, so all type checkers need to special case it.
defeq(left, right):
left_type=type(left)
right_type=type(right)
# if RHS is proper subtype of LHS, try RHS's equality methodifleft_type!=right_typeandissubclass(right_type, left_type):
result=right.__eq__(left)
ifresultisnotNotImplemented:
returnresult# try LHS's equality methodresult=left.__eq__(right)
ifresultisnotNotImplemented:
returnresult# try RHS's equality methodresult=right.__eq__(left)
ifresultisnotNotImplemented:
returnresultreturnFalse# fallback if all methods return NotImplemented
The Dilemma
This is too strict, because everything subclasses
objectand some classes may to wish to:bool(e.g. numpy array element-wise comparison, symbolic computation, etc.)On the other hand, many APIs (incorrectly) assume that
a == balways return abool, so changing the return type away fromboolcan lead to problems.Solving the Dilemma
Satisfying (1) is easy enough by changing
value: objecttovalue: Any. (one could maybe explore usingNeveralso)Satisfying (2) can be achieved in several ways, specifically I tested: (a)
-> object, (b)-> Anyand (c)-> Any | boolOption (a) leads to very bad primer result as per the dilemma explained above.
Option (b) triggers a lot of
no-any-returnwarnings withmypywhen a function does somethign likereturn a==b.Option (c) is essentially a cheat code that avoids the
no-any-returnwarnings from option (b)In particular, for (c) the primer actually looks really good. We have ~50 fixed
Unused "type: ignore" commenterrors, and 16 suprious[override]errors eliminated, without any new errors.References
Appendix: How python's
a==bworks internallyThis cannot be properly annotated with the current type system, so all type checkers need to special case it.