Re: Equality and relative ordering of objects
| From: | Michał Brzuchalski | Date: | Thu, 21 Jun 2018 12:31:19 +0000 |
| Subject: | Re: Equality and relative ordering of objects | ||
| References: | 1 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-102340@lists.php.net to get a copy of this message | ||
2018-06-21 11:27 GMT+02:00 Rudi Theunissen <rtheunissen@php.net>:
> The Comparable RFC (http://wiki.php.net/rfc/comparable) was written in
> 2010
> and
> revised in 2015 by Adam Harvey, but was not conclusive. I would like to
> take
> on some shared responsibility to push this forward and re-open the
> discussion.
>
> Why is this useful, and why should it be added to PHP?
>
>
> 1. The default comparison of objects can be expensive.
>
> Objects are compared and tested for equality by recursively comparing their
> properties. If an object has many properties, or properties that are
> objects
> or have large arrays, this comparison may dive very deep.
>
> It may not be necessary to do all this work to determine whether two
> objects
> are equal. For example, if you have a data model that represents a database
> entity, you're only concerned about the data attributes, and there's no
> need
> to compare the database connection or other internal metadata.
>
> Objects that have a defining value (like a number type), can simply compare
> itself in value to the other object (if also a number type), and can skip
> checking other properties. This has the potential to save a lot of
> unnecessary comparisons.
>
>
> 2. The default comparison of objects can be risky.
>
> There could be cases where two objects have the same public properties but
> one of them (perhaps a subclass) has a private property. These two objects
> could be considered equal to the outside world, but
== would
> return
> false. When a developer added this private property, it might
> not have
> been obvious that they were affecting equality. This makes ==
> checks on
> objects very fragile where it could be explictly defined and controlled.
>
>
> 3. There is no way to specify strict comparison.
>
> With PHP becoming more type-safe since PHP 7 with strict mode and scalar
> type-hints, the current behaviour feels out of date. For example:
>
> ```
> $a = new stdClass();
> $b = new stdClass();
>
> $a->prop = 1;
> $b->prop = true;
>
> $a == $b; // true
> ```
>
> 4. Adding this functionality does not affect backwards-compatibility and
> could
> probably be implemented in 5.x as well. To my knowledge, The only major
> changes required are in the default object handlers. This would
> automatically affect functions like array_search and
> sort.
>
>
> 5. Other major languages support this and there seems to be a decent amount
> of
> public support for it.
>
>
> What is the proposed API for this?
>
> Magic methods. Objects that don't implement them maintain the current
> behaviour.
>
> ```
> /**
> * @returns -1 if less than,
> * 0 if equal to,
> * 1 if greater than the other value (in terms of relative ordering).
> */
> __compareTo(mixed $other): int;
>
When comparing objects should be obvoius to use object type hint not
mixed
>
> /**
> * @returns true if this instance is equal to the given value, or false if
> not.
> */
> __equals(mixed $other): bool;
```
>
If __compareTo($other) gives 0 then there is no justification for
additional method.
IMO you're duplicating functionality here.
>
>
> Why magic methods?
>
> - No risk of breaking backwards compatibility because method names that
> start
> with __ are always reserved.
>
> - All objects can already be compared and tested for equality, so checking
> if
> an object implements an interface would not give you any useful
> information.
> Alternatively, we could introduce a function like "ÅIs
> K-Ù*™ß�ÂÓis_comparable.
>
> - Python uses magic methods because there are no interfaces. Java has a
> Comparable interface because not all objects are comparable by default.
> It's
> important to note that we're not exposing the ability to make an object
> comparable, but instead to change the default behaviour when compared. All
> objects are technically already comparable.
>
> - PHP already uses magic methods to change the default behaviour of
> objects.
>
> - Interfaces like Iterable or
> IteratorAggregate must be interfaces
> because
> not all objects are iterable.
>
>
> Why do we need __equals when
> __compareTo can just return 0?
>
> 1. Anything can be tested for equality, but all things are not comparable..
> For example, an apple can be equated with an orange and we can say that the
> apple does not equal the orange. However, comparing the apple to an orange
> makes no logical sense. There is nothing about either object that would
> allow us to say that the apple is greater or less than the orange.
>
> 2. Some things that are not equal have the same relative ordering. For
> example,
> a floating point value of 2.0 does not equal the integer
> 2, but
> their
> relative ordering is the same, and a comparison would return
> 0.
>
That's true, but you want to compare objects not scalar types, right?
>
> 3. The contexts in which they are called are not the same. Testing for
> equality
> occurs when an object is compared with another using == or in
> functions
> like array_search. The question we're asking is whether
> the two values
> are
> considered equal, and we're not concerned with ordering. The context for
> comparison is when we need to determine the relative ordering of two values
> using <, >, or in
> functions like sort.
>
>
> Issues to be discussed:
>
> 1. What happens when we use <= and
> >=? Does the "or equal to" part call
> __equals or does it check if
> __compareTo returns 0?
>
> 2. Should we also expose strict comparison, ie. === ?
>
> 3. Naming:
> - __eq
> - __equalTo
> - __equals
> - __compareTo
> - __comparedTo
> - __compare
> - __cmp
>
Thanks for reanimating this subject.
--
regards / pozdrawiam,
--
Michał Brzuchalski
about.me/brzuchal
brzuchalski.com