5 ms·
> you want a type error, not a return of False, when you check equality against a completely unrelated type What? No I don't? foo = if x: Foo else 1 f
by rattray 6y ago
> you want a type error, not a return of False, when you check equality against a completely unrelated type
What? No I don't?
foo = if x: Foo else 1
foo == 1 # why would I want this to throw? I just want False!
Disclaimer that I haven't done much Python recently (or Java, ever – I wonder if raise-on-== is a java-ism)
- marcosdumay 6y agoThe Python stdlib all seems to disagree with the GP and provide False for comparisons with values of different types. Personally, I didn't expect this, because Python tends to not like mixing types in any way, but it's the one place where it makes sense.
- bobbiechen 6y agoYup, that's true. In Python, generally if you want to only compare equal to the same type, you would use the NotImplemented value to implement: class MyClass: def __eq__(self, other): if not isinstance(other, MyClass): return NotImplemented else: # whatever your comparison is When NotImplemented is returned, there is a fallback sequence described in https://docs.python.org/3/library/numbers.html#implementing-the-arithmetic-operations https://docs.python.org/3/library/numbers.html#implementing-... - where basically, in the expression `A == B`, if `A.__eq__(B)` returns NotImplemented, then `B.__eq__(A)` is checked as well (falling back to an `is` identity comparison if both return NotImplemented). This is neat because it allows you to define a class B that can compare equal to an existing class A with the expression A == B, even though class A has no knowledge of B.
- wk_end 6y agoYou don't want it to raise an exception at run-time, but you probably want it to be a static type error: two things that aren't the same type can never be equal, so if you're bothering to compare them you're at best wasting cycles and at worst making a dumb mistake. In your example, `foo` could be marked (in mypy) a `Union[Foo, int]`, which would be a reasonable value to compare against an `int` and not a type error.
- joshuamorton 6y agoBut there are times you want heterogenous types to compare with ==. Your approach isn't compatible with ad-hoc polymorphism. For an example, consider `np.eye(4) == 1`. In this, you're comparing a doubly nested array of floats with a scalar int, but the operation is well defined (vectorized equality comparison). And yes, it should be feasible to typecheck that operation.
- coldtea 6y ago>two things that aren't the same type can never be equal Well, actually as long as they implement the right dundermethods, they can totally be.
- codethief 6y agoBesides, there is a difference between the actual type of the objects `a` and `b` in `a == b` and the structural type you specify in an annotation. For instance: from typing import Protocol class MyClass: def method_a(self) -> None: ... def method_b(self) -> None: ... class ProtocolA(Protocol): def method_a(self) -> None: ... class ProtocolB(Protocol): def method_b(self) -> None: ... def compare(a: ProtocolA, b: ProtocolB): if a == b: print("a == b") else: print("a != b") a = MyClass() b = MyClass() compare(a, b) Clearly, you would expect the output to be "a == b".
- magicalhippo 6y ago> two things that aren't the same type can never be equal You're saying is that an 8-bit number can never be equal to a 16-bit number, or a 32-bit number, or a... I hope you agree that's ridiculous.
- cygx 6y agoI hope you agree that's ridiculous. No comparison without explicit casts is a valid design choice. I think Ada and Rust work that way, though I've never used either language and might be mistaken...
- chriswarbo 6y ago> I wonder if raise-on-== is a java-ism There are two forms of equality in Java: - 'x == y' is an identity check, like 'x is y' in Python (are x and y referencing the same memory?). These must be of the same type, or else it won't compile. - 'x.equals(y)' is an overridable method, like 'x == y' in Python. Its argument is of type 'Object', so it will accept anything. I don't do much Java these days, but I do write a lot of Scala (which runs on the JVM). One of the first things I do in a Scala project is load the 'cats' package so I can use 'x.eqv(y)' which refuses to compile if x and y are of incompatible types. This problem also propagates up through different APIs, e.g. 'x.contains(y)' checks whether y appears in the collection x (which could be a list, hashmap, etc.); this doesn't check the types, and I've ended up with bugs that would have been caught if it were stricter. I now prefer to define a safer alternative 'x.has(y)' which uses 'x.exists(z => z.eqv(y))'.