On Thu, May 07, 2020 at 11:04:16AM -0400, Dan Sommers wrote:
> On Thu, 7 May 2020 21:18:16 +1000
> Steven D'Aprano <st...@pearwood.info> wrote:
> 
> > > The strongest equality is the "is" operator
> > 
> > Please don't encourage the conceptual error of thinking of `is` as 
> > *equality*, not even a kind of equality. It doesn't check for equality, 
> > it checks for *identity* and we know that there is at least one object 
> > in Python where identical objects aren't equal:
> > 
> >     py> from math import nan
> >     py> nan is nan
> >     True
> >     py> nan == nan
> >     False
> 
> We'd better agree to disagree on this one.

Why? In what way is there any room for disagreement at all?

This isn't a matter of subjective opinion, like what's the best Star 
Wars film or whether pineapple belongs on pizza. This is a matter of 
objective fact, like whether Python strings are Unicode or not.

Whatever we might feel about equality and identity in the wider 
philosophical sense, in the *Python programming sense* the semantic 
meaning of the two operators are orthogonal:

* some equal objects are not identical;
* and some identical objects are not equal.

It is a matter of fact that in Python `is` tests for object identity, 
not equality:

https://docs.python.org/3/reference/expressions.html#is-not

If you wish to agree with Bertrand Meyer that reflexivity of equality is 
one of the pillars of civilization:

https://bertrandmeyer.com/2010/02/06/reflexivity-and-other-pillars-of-civilization/

and therefore Python gets equality wrong, you are welcome to that 
opinion, but whether we like it or not equality in Python is not 
necessarily reflexive and as a consequence objects may be identical 
(i.e. the same object) but not equal. Float and Decimal NANs are the 
most obvious examples.

You don't even need to look at such exotic objects as NANs to see that 
`is` does not test for equality. None of these will return True:

    [] is []
    1.5 is Fraction(3, 2)
    (a := {}) is a.copy()

even though the operands are clearly equal.


[...]
> YAGNI is how I feel about an operator that compares sequences element by
> element.

Remember that list-to-list and tuple-to-tuple already perform the same 
sequence element-by-element comparison.

All this proposal adds is *duck-typing* to the comparison, for when 
it doesn't matter what the container type is, you care only about the 
values in the container. Why be forced to do a possibly expensive (and 
maybe very expensive!) manual coercion to a common type just to check 
the values for equality element by element, and then throw away the 
coerced object?

If you have ever written `a == list(b)` or similar, then You Already 
Needed It :-)


> People can write their own functions.  :-)  Or add your .EQ.
> function to the standard library (or even to builtins, and no, I don't
> have a good name).

True, but there are distinct advantages to operators over functions for 
some operations. See Guido's essay:

https://neopythonic.blogspot.com/2019/03/why-operators-are-useful.html


> > It is only that wanting to compare two ordered containers for equality
> > of their items without regard to the type of container is a reasonably
> > common and useful thing to do.
> 
> > Even if we don't want list==tuple to return True -- and I don't! -- we
> > surely can recognise that sometimes we don't care about the
> > container's type, only it's elements.
> 
> Do "reasonably common," "useful," and "sometimes" meet the bar for a new
> operator?  (That's an honest question and not a sharp stick.)

It depends on how common and useful, and how easy it is to find a good 
operator. It might be a brilliant idea stymied by lack of a good 
operator.

We might be forced to use a function because there are no good operators 
left any more, and nobody wants Python to turn into Perl or APL.

 
> FWIW, I agree:  list != tuple.  When's the last time anyone asked for
> the next element of a tuple?

Any time you have written:

    for obj in (a, b, c): ...

you are asking for the next element of a tuple.

A sample from a test suite I just happen to have open at the moment:

    # self.isprime_functions is a tuple of functions to test
    for func in self.isprime_functions:

    for a in (3, 5, 6):
        self.assertFalse(sqrt_exists(a, 7))
    for a in (2, 6, 7, 8, 10):
        self.assertFalse(sqrt_exists(a, 11))


-- 
Steven
_______________________________________________
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/ABSJEK5QQQCBSG3PU7L3BS7NE3KMG4V6/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to