Hi all,
Those of you with long memories will remember that I proposed a
Comparable interface way back in the pre-5.4 days, but withdrew it
when it became obvious that there was no consensus for it as a feature
and that a vote was likely to fail.
RFC: https://wiki.php.net/rfc/comparable
PR: https://github.com/php/php-src/pull/1097
Why reanimate it now, I hear you ask? I think that comparisons have
only become more prominent in the language: we now have a spaceship
operator for explicit comparisons, yet the behaviour of object
comparisons can be obscure, to say the least, and the user has no
control over how their objects are compared.
At this stage, I intend to put this up for a vote on March 5 (vote
ending March 12), with the obvious endgame being that this would be
included in 7.0.
Thanks,
Adam
Those of you with long memories will remember that I proposed a
Comparable interface way back in the pre-5.4 days, but withdrew it
when it became obvious that there was no consensus for it as a feature
and that a vote was likely to fail.RFC: https://wiki.php.net/rfc/comparable
PR: https://github.com/php/php-src/pull/1097Why reanimate it now, I hear you ask? I think that comparisons have
only become more prominent in the language: we now have a spaceship
operator for explicit comparisons, yet the behaviour of object
comparisons can be obscure, to say the least, and the user has no
control over how their objects are compared.At this stage, I intend to put this up for a vote on March 5 (vote
ending March 12), with the obvious endgame being that this would be
included in 7.0.
If the responsibility of comparing two objects is pushed into the
objects themselves then the ability to use different comparison
criteria for the same two objects when placing them in two different
structures is taken away. This is actually a very common problem I
have seen people complain about in Java.
Another issue: it allows comparing an object to non-objects (even
though the stated goal is only to compare two objects of the same
type):
class MyClass implements Comparable {
private $val = 0;
function compareTo($a) {
return $this->val <=> $a;
}
}
$int = 10;
$myClass = new MyClass();
$myClass <=> $int; // works
$int <=> $myClass; // if this doesn't produce a warning it at least
doesn't behave the same as the line above it
Ultimately, when comparing two objects it is usually as part of some
algorithm, so instead the Comparator interface could be used:
interface Comparator {
function compare($a, $b): int;
}
But even here I would rather just take a function instead of requiring
it to be the instance of some interface:
function sort($input, callable $comparator($a, $b): int) {
/* … */
}
All in all, I don't think the fundamental idea of the RFC is good. The
Comparable interface is inferior to many other techniques of achieving
the same goal of comparing two objects.
I do want to thank you for taking the time to cite arguments, prior
history and an alternative in the RFC. You have done a pretty good job
on the RFC itself, in my opinion.
I don't want to get into a lengthy debate (you have your opinion; I
have mine!), but to rebut a couple of specific points:
Another issue: it allows comparing an object to non-objects (even
though the stated goal is only to compare two objects of the same
type):
This is intentional. The wording in the introduction is probably a
little too specific to the object case — I'll fix that.
class MyClass implements Comparable {
private $val = 0;
function compareTo($a) {
return $this->val <=> $a;
}
}$int = 10;
$myClass = new MyClass();
$myClass <=> $int; // works
$int <=> $myClass; // if this doesn't produce a warning it at least
doesn't behave the same as the line above it
It does behave the same as the line above (with the result inverted,
obviously) — MyClass::compareTo() is still called in this case. The
only time ordering matters is if two objects are being compared, in
which case the leftmost one is the one that has its compareTo() method
called.
But even here I would rather just take a function instead of requiring
it to be the instance of some interface:function sort($input, callable $comparator($a, $b): int) {
/* … */
}
Fair, but the sorting case isn't the only one that matters,
particularly with <=> now as part of the language.
I do want to thank you for taking the time to cite arguments, prior
history and an alternative in the RFC. You have done a pretty good job
on the RFC itself, in my opinion.
Thanks. :)
Adam
But even here I would rather just take a function instead of requiring
it to be the instance of some interface:function sort($input, callable $comparator($a, $b): int) {
/* … */
}Fair, but the sorting case isn't the only one that matters,
particularly with <=> now as part of the language.
For completeness: I advocate accepting a comparator in every case
where custom comparison logic is needed, not just for sorting.
Hi all,
Those of you with long memories will remember that I proposed a
Comparable interface way back in the pre-5.4 days, but withdrew it
when it became obvious that there was no consensus for it as a feature
and that a vote was likely to fail.RFC: https://wiki.php.net/rfc/comparable
PR: https://github.com/php/php-src/pull/1097Why reanimate it now, I hear you ask? I think that comparisons have
only become more prominent in the language: we now have a spaceship
operator for explicit comparisons, yet the behaviour of object
comparisons can be obscure, to say the least, and the user has no
control over how their objects are compared.At this stage, I intend to put this up for a vote on March 5 (vote
ending March 12), with the obvious endgame being that this would be
included in 7.0.Thanks,
Thanks you :)
I like it. It is simple and straightforward.
I agree with other that it is easily done using a simple function
(Adam's) but I do not like it much, less clear.
Cheers,
Pierre
@pierrejoye | http://www.libgd.org
Hi Adam,
Am 19.02.2015 um 22:40 schrieb Adam Harvey:
RFC: https://wiki.php.net/rfc/comparable
PR: https://github.com/php/php-src/pull/1097
I see a little problem here by allowing any comparison. Comparing is
used for ordering, but you can easily construct ordering mechanisms that
simply don't work:
class A implements Comparable {
public $value;
function compareTo($other) {
if ($other instanceof A) {
return $this->value <=> $other->value;
} else {
return -1;
}
}
}
class B implements Comparable {
public $value;
function compareTo($other) {
if ($other instanceof B) {
return $this->value <=> $other->value;
} else {
return -1;
}
}
}
$a = new A();
$a->value = 1;
$b = new B();
$b->value = 2;
$a->compareTo($b); // -1
$b->compareTo($a); // -1
If you now have a mixed list of objects of A and B, the actual order in
the list completely depends whether A's compareTo() method is called or
B's compareTo() method.
I think comparison should always be symmetric:
$a < $b <=> $b > $a
Otherwise the behavior is nearly unpredictable/random.
As we have no method overloading, the only viable option I see is to
only allow comparison of objects of the same type.
Thanks
Dennis
Those of you with long memories will remember that I proposed a
Comparable interface way back in the pre-5.4 days, but withdrew it
when it became obvious that there was no consensus for it as a feature
and that a vote was likely to fail.RFC: https://wiki.php.net/rfc/comparable
PR: https://github.com/php/php-src/pull/1097
Afaik \DateTime object already implement a way to be used with <,>,etc.
but they don't use an interface for that.
$ php -r '$past = new DateTime("-1 month"); $future = new DateTime("+1
month"); var_dump($past < $future);'
bool(true)
$ php -r '$past = new DateTime("-1 month"); $future = new DateTime("+1
month"); var_dump($past > $future);'
bool(false)
Shouldn't they retroactively be adopted to that? Extend from that
Interface, implement a compoareTo?
- Markus
Hi all,
Those of you with long memories will remember that I proposed a
Comparable interface way back in the pre-5.4 days, but withdrew it
when it became obvious that there was no consensus for it as a feature
and that a vote was likely to fail.RFC: https://wiki.php.net/rfc/comparable
PR: https://github.com/php/php-src/pull/1097Why reanimate it now, I hear you ask? I think that comparisons have
only become more prominent in the language: we now have a spaceship
operator for explicit comparisons, yet the behaviour of object
comparisons can be obscure, to say the least, and the user has no
control over how their objects are compared.At this stage, I intend to put this up for a vote on March 5 (vote
ending March 12), with the obvious endgame being that this would be
included in 7.0.
Some technical notes on the RFC text:
- "How it is ensured that if $a < $b then $b > $a?" The RFC claims that it
is up to the developer to ensure this, however I don't think this is true.
As far as I know PHP will implicitly enforce this. It would be good if you
could double-check the behavior. - "If both $a and $b are objects with different compare functions, how it
is determined whose function is used" Here you answer that the left operand
wins. Once again I am unsure whether this is true - I'd assume that for >
and >= the right operand wins. - I would appreciate a note that indicates how non-total /
non-trichotomous comparisons can be implemented, namely by returning 1
irregardless of order. You can use a subset-relationship to illustrate this. - Have you considered the impact on exception-safety this may have? Did
you verify that all places where compare_function (or derivatives) are used
are exception-safe?
Nikita