mentalisttraceur / python-macaddress

BSD Zero Clause License
19 stars 5 forks source link

Notes on Avoiding Accidentally Inconsistently Transitive Equality #24

Closed mentalisttraceur closed 2 years ago

mentalisttraceur commented 2 years ago

This does not effect any released version. I just wanted to jot down some thoughts about this design pitfall that I almost made with this library back when I first started it.

The behavior which I originally documented in the docstring of __eq__, but luckily accidentally did not implement, was that hardware address instances were equal if one was a subclass of the other (unless the subclass had a different size for some reason).

Now that sounds pretty reasonable at face value, doesn't it? Substitution principle - subclass instances should be usable as a parent class instance, and that includes equality.

I even implemented the "fixed" version (but never merged or released) in commit bdb4d260a767d821a84ce8d903e9eb45af143443, in case you want to play with it.

Here's the thing though: it would've resulted in this behavior:

>>> from macaddress import *
>>> class MAC1(EUI48): pass
...
>>> MAC1(0) == MAC1(0)
True
>>> MAC1(0) == EUI48(0)
True
>>> class MAC2(EUI48): pass
...
>>> MAC2(0) == EUI48(0)
True
>>> MAC2(0) == EUI48(0) == MAC1(0)
True
>>> MAC2(0) == MAC1(0)
False
>>> MAC2(0) == MAC1(0) == EUI48(0)
False

That should raise some alarms. foo == bar == qux is true but foo == qux == bar is false!?

This kind of inconsistency would've been a terrible API pitfall - most users would not expect equality to work this way, and the common case would absolutely lead to people forming expectations that equality is transitive.