On Sat, 2 May 2020 at 20:50, Serhiy Storchaka <storch...@gmail.com> wrote:
>
> 02.05.20 21:34, Ahmed Amr пише:
> > I see there are ways to compare them item-wise, I'm suggesting to bake
> > that functionality inside the core implementation of such indexed
> > structures.
> > Also those solutions are direct with tuples and lists, but it wouldn't
> > be as direct with arrays-lists/tuples comparisons for example.
>
> If make `(1, 2, 3) == [1, 2, 3]` we would need to make `hash((1, 2, 3))
> == hash([1, 2, 3])`.

This is the key point. Much of the other discussion in this thread
seems to be bogged down in the mathematical interpretation of tuples
and sequences but if I was to take something from maths here it would
be the substitution principle of equality:
https://en.wikipedia.org/wiki/Equality_(mathematics)#Basic_properties

What the substitution principle essentially says is
   if x == y then f(x) == f(y)
for any function f such that f(x) is well defined.

What that means is that I should be able to substitute x for y in any
context where x would work without any change of behaviour. We don't
need to do any deep maths to see how that principle can be applied in
Python but if you try to follow it rigorously then you'll see that
there are already counterexamples in the language for example

>>> x = 1000
>>> y = 1000.0
>>> f = lambda z: 100**z
>>> x == y
True
>>> f(x) # fine
<snip>
>>> f(y) # not fine
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <lambda>
OverflowError: (34, 'Result too large')

Given a list x and a tuple y with equivalent elements x and y will not
be interchangeable because one is not hashable and the other is not
mutable so there are functions where one is usable but the other is
not. Following the same reasoning set/frozenset should not compare
equal.

In SymPy there are many different mathematical objects that people
feel should (on mathematical grounds) compare "equal". This happens
enough that there is a section explaining this in the tutorial:
https://docs.sympy.org/latest/tutorial/gotchas.html#equals-signs
The terms "structural equality" and "mathematical equality" are used
to distinguish the different kinds of equality with == being used for
the structural sense.

For example the sympy expression Pow(2, 2, evaluate=False) gives an
object that looks like 2**2. This does mathematically represent the
number 4 but the expression itself is not literally the number 4 so
the two expressions are mathematically equal but not structurally
equal:

>>> from sympy import Pow
>>> p = Pow(2, 2, evaluate=False)
>>> p
2**2
>>> p.doit()
4
>>> p == 4
False
>>> p.doit() == 4
True

This distinction is important because at the programmatic level p and
4 are not interchangeable. For example p being a Pow has attributes
base and exp that 4 will not have. In sympy most objects are immutable
and hashable and are heavily used in sets and dicts. Following the
substitution principle matters not least because Python has baked the
use of ==/__eq__ into low-level data structures so objects that
compare equal with == will literally be interchanged:

>>> {1, 1.0}
{1}
>>> {1.0, 1}
{1.0}

All the same many sympy contributors have felt the need to define
__eq__ methods that will make objects of different types compare equal
and there are still examples in the sympy codebase. These __eq__
methods *always* lead to bugs down the line though (just a matter of
time).

I've come to the seemingly obvious conclusion that if there is *any*
difference between x and y then it's always better to say that x != y.


Oscar
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/ZBTK2RSH3QVHCJY42JNBIFEYTO6LERLS/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to