Skip to content

How should type checkers type check equality? #378

@JukkaL

Description

@JukkaL

Right now typeshed defines equality to be defined for each pair of types, even though something like n == (m,) is almost certainly a bug if both n and m are integers, for example. There is no runtime error, so not rejecting it would also be somewhat reasonable (also, a subclass of int might plausibly return True when compared against a tuple, though this more of a theoretical concern). It's unclear how type checkers should deal with these. As equality checking is very common, and anecdotally errors related to equality checking are not infrequent, we may want to spell out how this should be done in PEP 484, so that all tools would handle these consistently.

Here are some options:

  • Leave it up to individual type checkers to figure this out, and make the signatures of __eq__ and __ne__ accept arbitrary objects.
  • Make the signatures of __eq__ and __ne__ accept arbitrary objects, but require type checkers to have special, well-defined rules for type checking == and != operations so that we can reject n == (m,) and other similar cases consistently.
  • Encode the information about what a particular type can be equal to in the signature of __eq__ and __ne__. This may require special rules for these methods, since we may want to narrow down the argument type in a subclass (as it should be possible to compare object to object), but normally method argument types vary contravariantly so this is not allowed. For example, int.__eq__ would only accept int arguments, since this seems to return NotImplemented for other argument types. It's still unclear what the exact rules for type checking __eq__ and __ne__ should be.
  • Add a new type system concept to PEP 484 and typing to represent "comparable types" or "equatable types". For example, I might want to define function isequal(x, y) that takes two arguments that can be of arbitrary types as long as they might compare equal to each other. isequal(1, 1.1) should be okay but isequal(1, 'x') should be rejected. We'd then use this concept to type check == and != as well. This could be useful for things like __contains__. If the result of an in operation is known to be False statically, we should perhaps reject it as well.

Also see python/mypy#1271 and the conversation in python/typeshed#874.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions