Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tighten strictness on operators #574

Open
KotlinIsland opened this issue Nov 7, 2023 · 1 comment
Open

tighten strictness on operators #574

KotlinIsland opened this issue Nov 7, 2023 · 1 comment
Labels

Comments

@KotlinIsland
Copy link
Owner

KotlinIsland commented Nov 7, 2023

from datetime import date

a: date
if a == "a":  # no error
    print("hi")

This issue is that operators tend to be implemented like:

class A:
    def __eq__(self, other: object) -> bool:
        if not isinstance(other, A):
            return NotImplemented
        return ...

Ideal analysis would be:

class A:
    def __eq__(self, other):
        if not isinstance(other, A):
            return NotImplemented
        return ...
class B:
    def __eq__(self, other):
        if not isisntance(other, B | A):
            return NotImplemented
        return ...
a: A
b: B
a == 1  # error
1 == a  # error
b == 1  # error
1 == b  # error
a == b  # no error
b == a  # no error

Solution:

you annotate the compatible types, and they become object in the implementation:

class A:
    def __eq__(self, other: Self) -> bool:
        reveal_type(other)  # object
        
class B:
    def __eq__(self, other: Self | A) -> bool:
        reveal_type(other)  # object

Although, every __eq__ that exists in the world today is other: object, so we won't get much benefit :(

We might need to examine the implementation to get a nice type. (#453)

@DetachHead
Copy link
Collaborator

could this be fixed by updating the __eq__ from object to only allow Self:

def __eq__(self, __value: Self) -> bool: ...

because currently since it takes object no subtypes can override it with something more specific. your example currently doesnt work for that reason:

class SupportsEq(Protocol[T]):
    @override
    def __eq__(self, other: T) -> bool: ... # error: error: Argument 1 of "__eq__" is incompatible with supertype "object"; supertype defines the argument type as "object"

but if object's __eq__ used the Self type, then a subtype could just do this and there'd be no issue:

class A:
    @override
    def eq(self, other: Self | int) -> bool: ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants