[RFC] Combined Comparison Operator

php.internals

Davey

12 years ago
Hey folks, I've written up an RFC/Patch to gauge interest and get feedback on the addition of a combined comparison (aka: spaceship) operator. You can see the RFC at: https://wiki.php.net/rfc/combined-comparison-operator This adds a new operator "(expr) <=> (expr)" that returns 0 if both operands are equal, 1 if the left is greater, and -1 if the right is greater. It works with all types (just as well as <, <=, >=, > work) and is great for usort() callbacks for example. Code available here (against 5.6): https://github.com/dshafik/php-src/compare/add-spaceship-operator I'd love to get this into 5.6, not sure if we hit feature freeze yet. Also, not sure if it needs 2/3 majority, but assumed so as pow did? Thoughts? If there is interest, I'll start adding tests. They should be fairly trivial. - Davey

Andrew Faulds

12 years ago
On 13/02/14 03:58, Davey Shafik wrote:
> This adds a new operator "(expr) <=> (expr)" that returns 0 if both > operands are equal, 1 if the left is greater, and -1 if the right is > greater. > > It works with all types (just as well as <, <=, >=, > work) and is great > for usort() callbacks for example.
It's useful and cool, and adds an awesome new operator name ((T_SPACESHIP <=> T_PAAMAYIM_NEKUDOTAYIM) === 1), but would it be used often enough to justify addition?
-- Andrea Faulds http://ajf.me/

Yasuo Ohgaki

12 years ago
Hi Davey, On Thu, Feb 13, 2014 at 12:58 PM, Davey Shafik <davey@php.net> wrote:
> I've written up an RFC/Patch to gauge interest and get feedback on the > addition of a combined comparison (aka: spaceship) operator. > > You can see the RFC at: https://wiki.php.net/rfc/ > combined-comparison-operator > > This adds a new operator "(expr) <=> (expr)" that returns 0 if both > operands are equal, 1 if the left is greater, and -1 if the right is > greater. > > It works with all types (just as well as <, <=, >=, > work) and is great > for usort() callbacks for example. > > Code available here (against 5.6): https://github.com/dshafik/ > php-src/compare/add-spaceship-operator > > I'd love to get this into 5.6, not sure if we hit feature freeze yet. > Also, not sure if it needs 2/3 majority, but assumed so as pow did? > > Thoughts? > > If there is interest, I'll start adding tests. They should be fairly > trivial. >
Interesting shortcut operator. I feel closure function is for the task. I would vote 0, but close to -1 since it's only useful for sorting. Is there any other use cases? Regards,
-- Yasuo Ohgaki yohgaki@ohgaki.net

Davey

12 years ago
On 2/12/14, 11:25 PM, Yasuo Ohgaki wrote:
> Hi Davey, > > On Thu, Feb 13, 2014 at 12:58 PM, Davey Shafik <davey@php.net> wrote: > >> I've written up an RFC/Patch to gauge interest and get feedback on the >> addition of a combined comparison (aka: spaceship) operator. >> >> You can see the RFC at: https://wiki.php.net/rfc/ >> combined-comparison-operator >> >> This adds a new operator "(expr) <=> (expr)" that returns 0 if both >> operands are equal, 1 if the left is greater, and -1 if the right is >> greater. >> >> It works with all types (just as well as <, <=, >=, > work) and is great >> for usort() callbacks for example. >> >> Code available here (against 5.6): https://github.com/dshafik/ >> php-src/compare/add-spaceship-operator >> >> I'd love to get this into 5.6, not sure if we hit feature freeze yet. >> Also, not sure if it needs 2/3 majority, but assumed so as pow did? >> >> Thoughts? >> >> If there is interest, I'll start adding tests. They should be fairly >> trivial. >> > > Interesting shortcut operator. > I feel closure function is for the task. > I would vote 0, but close to -1 since it's only useful for sorting. > Is there any other use cases? > > Regards, > > -- > Yasuo Ohgaki > yohgaki@ohgaki.net >
Yasuo, Sorting is definitely it's most compelling use. It cuts down on potentially quite a bit of code: function ($left, $right) { if ($left[1] == $right[1]) { return 0; } if ($left[1] > $right[1]) { return 1; } if ($left[1] < $right[1]) { return -1; } } or (as per the RFC): function ($left, $right) { return $left[1] <=> $right[1]; }

Simon J Welsh

12 years ago
On 13/02/2014, at 17:39, Davey Shafik <davey@php.net> wrote:
> On 2/12/14, 11:25 PM, Yasuo Ohgaki wrote: >> Hi Davey, >> >> On Thu, Feb 13, 2014 at 12:58 PM, Davey Shafik <davey@php.net> wrote: >> >>> I've written up an RFC/Patch to gauge interest and get feedback on the >>> addition of a combined comparison (aka: spaceship) operator. >>> >>> You can see the RFC at: https://wiki.php.net/rfc/ >>> combined-comparison-operator >>> >>> This adds a new operator "(expr) <=> (expr)" that returns 0 if both >>> operands are equal, 1 if the left is greater, and -1 if the right is >>> greater. >>> >>> It works with all types (just as well as <, <=, >=, > work) and is great >>> for usort() callbacks for example. >>> >>> Code available here (against 5.6): https://github.com/dshafik/ >>> php-src/compare/add-spaceship-operator >>> >>> I'd love to get this into 5.6, not sure if we hit feature freeze yet. >>> Also, not sure if it needs 2/3 majority, but assumed so as pow did? >>> >>> Thoughts? >>> >>> If there is interest, I'll start adding tests. They should be fairly >>> trivial. >>> >> >> Interesting shortcut operator. >> I feel closure function is for the task. >> I would vote 0, but close to -1 since it's only useful for sorting. >> Is there any other use cases? >> >> Regards, >> >> -- >> Yasuo Ohgaki >> yohgaki@ohgaki.net >> > > Yasuo, > > Sorting is definitely it's most compelling use. It cuts down on potentially quite a bit of code: > > function ($left, $right) { > if ($left[1] == $right[1]) { > return 0; > } > > if ($left[1] > $right[1]) { > return 1; > } > > if ($left[1] < $right[1]) { > return -1; > } > } > > or (as per the RFC): > > function ($left, $right) { > return $left[1] <=> $right[1]; > } > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php
The only real case I see for this is to save some boilerplate when dealing with arrays. Strings have strcmp(), numbers have subtraction and when you’re sorting objects, you probably want to be doing the comparison on some string/numeric property. If you really need the -1/0/1 return value (sorting functions don’t), then wrap the strcmp/subtraction in a trivial sign() function. --- Simon Welsh Admin of http://simon.geek.nz/

Johannes Schlueter

12 years ago
On Wed, 2014-02-12 at 23:39 -0500, Davey Shafik wrote:
> function ($left, $right) { > if ($left[1] == $right[1]) { > return 0; > } > > if ($left[1] > $right[1]) { > return 1; > } > > if ($left[1] < $right[1]) { > return -1; > } > } > > or (as per the RFC): > > function ($left, $right) { > return $left[1] <=> $right[1]; > } >
while that example is overly nice - in real world outside a usort callback the consumer of the function in most cases still has to do the three if cases to use the result. So in practical terms it is limited to usort() and then it is a custom operator people reading the code most likely have to lookup. Typically in PHP we try to have identifiers which can be found via Google, Google doesn't handle "special" characters well. johannes

Christian Stoller

12 years ago
Davey Shafik <davey@php.net> wrote:
> This adds a new operator "(expr) <=> (expr)" that returns 0 if both > operands are equal, 1 if the left is greater, and -1 if the right is > greater. > > It works with all types (just as well as <, <=, >=, > work) and is great > for usort() callbacks for example. >
Why not using `$a - $b` instead of `$a <=> $b`? Simon J Welsh <simon@simon.geek.nz> wrote:
> The only real case I see for this is to save some boilerplate when > dealing with arrays. Strings have strcmp(), numbers have subtraction > And when you’re sorting objects, you probably want to be doing > the comparison on some string/numeric property. >
Agreed! It would make more sense to write a comparison function for arrays/objects. Best regards Christian

Tjerk Meesters

12 years ago
On Thu, Feb 13, 2014 at 3:19 PM, Christian Stoller <stoller@leonex.de>wrote:
> Davey Shafik <davey@php.net> wrote: > > This adds a new operator "(expr) <=> (expr)" that returns 0 if both > > operands are equal, 1 if the left is greater, and -1 if the right is > > greater. > > > > It works with all types (just as well as <, <=, >=, > work) and is great > > for usort() callbacks for example. > > > > Why not using `$a - $b` instead of `$a <=> $b`? >
This only works on numbers, and integers in particular, because of how the result of a comparison function is cast. For example, `0.4f - 0.5f` equals `-0.1f` but gets cast to `0` when it's converted to a long value. See also: http://lxr.php.net/xref/PHP_5_6/ext/standard/array.c#597
> > Simon J Welsh <simon@simon.geek.nz> wrote: > > The only real case I see for this is to save some boilerplate when > > dealing with arrays. Strings have strcmp(), numbers have subtraction > > And when you're sorting objects, you probably want to be doing > > the comparison on some string/numeric property. > > > > Agreed! It would make more sense to write a comparison function for > arrays/objects. > > > Best regards > Christian >
-- -- Tjerk

Davey

12 years ago
On 2/13/14, 2:19 AM, Christian Stoller wrote:
> Davey Shafik <davey@php.net> wrote: >> This adds a new operator "(expr) <=> (expr)" that returns 0 if both >> operands are equal, 1 if the left is greater, and -1 if the right is >> greater. >> >> It works with all types (just as well as <, <=, >=, > work) and is great >> for usort() callbacks for example. >> > > Why not using `$a - $b` instead of `$a <=> $b`? > > > Simon J Welsh <simon@simon.geek.nz> wrote: >> The only real case I see for this is to save some boilerplate when >> dealing with arrays. Strings have strcmp(), numbers have subtraction >> And when you’re sorting objects, you probably want to be doing >> the comparison on some string/numeric property. >> > > Agreed! It would make more sense to write a comparison function for arrays/objects. > > > Best regards > Christian >
This operator DOES work on arrays/objects. The fact it also works on scalar values is a bonus if that's how you want to look at it :P - Davey

Pierre Joye

12 years ago
Hi David, Thanks for this proposal. On Feb 13, 2014 10:30 PM, "Davey Shafik" <davey@php.net> wrote:
> > On 2/13/14, 2:19 AM, Christian Stoller wrote: >> >> Davey Shafik <davey@php.net> wrote: >>> >>> This adds a new operator "(expr) <=> (expr)" that returns 0 if both >>> operands are equal, 1 if the left is greater, and -1 if the right is >>> greater. >>> >>> It works with all types (just as well as <, <=, >=, > work) and is great >>> for usort() callbacks for example. >>> >> >> Why not using `$a - $b` instead of `$a <=> $b`? >> >> >> Simon J Welsh <simon@simon.geek.nz> wrote: >>> >>> The only real case I see for this is to save some boilerplate when >>> dealing with arrays. Strings have strcmp(), numbers have subtraction >>> And when you’re sorting objects, you probably want to be doing >>> the comparison on some string/numeric property. >>> >> >> Agreed! It would make more sense to write a comparison function for
arrays/objects.
>> >> >> Best regards >> Christian >> > > This operator DOES work on arrays/objects. The fact it also works on
scalar values is a bonus if that's how you want to look at it :P This new operator doea not look too useful to me but here is one comment about objects handling: It compares only values, seems to be the only solution but the actual usage for that is rather inexistent as it compares apples and pears, or am I missing something? Cheers, Pierre

Davey

12 years ago
On 2/13/14, 12:14 PM, Pierre Joye wrote:
> Hi David, > > Thanks for this proposal. > > On Feb 13, 2014 10:30 PM, "Davey Shafik" <davey@php.net> wrote: >> >> On 2/13/14, 2:19 AM, Christian Stoller wrote: >>> >>> Davey Shafik <davey@php.net> wrote: >>>> >>>> This adds a new operator "(expr) <=> (expr)" that returns 0 if both >>>> operands are equal, 1 if the left is greater, and -1 if the right is >>>> greater. >>>> >>>> It works with all types (just as well as <, <=, >=, > work) and is great >>>> for usort() callbacks for example. >>>> >>> >>> Why not using `$a - $b` instead of `$a <=> $b`? >>> >>> >>> Simon J Welsh <simon@simon.geek.nz> wrote: >>>> >>>> The only real case I see for this is to save some boilerplate when >>>> dealing with arrays. Strings have strcmp(), numbers have subtraction >>>> And when you’re sorting objects, you probably want to be doing >>>> the comparison on some string/numeric property. >>>> >>> >>> Agreed! It would make more sense to write a comparison function for > arrays/objects. >>> >>> >>> Best regards >>> Christian >>> >> >> This operator DOES work on arrays/objects. The fact it also works on > scalar values is a bonus if that's how you want to look at it :P > > This new operator doea not look too useful to me but here is one comment > about objects handling: > > It compares only values, seems to be the only solution but the actual usage > for that is rather inexistent as it compares apples and pears, or am I > missing something? > > Cheers, > Pierre >
So, this behavior can definitely be changed — preserving the current behavior of == for the 0 value, and then we can go two different ways for 1/-1: - Compare only like-for-like keys, ignoring extra keys - Compare like-for-like keys, and count the number of additional keys are being great. So: if they match on all common keys, but left has 3 additional keys, and right has 4, right is greater than left. It's definitely tough to get the semantics right. But: the behavior is also currently identical to $obj <= $obj2, etc. I felt that consistency was most important. The logical next step with this operator is to add a "Comparable" "interface" like ruby (not saying it has to be an interface, magic method also works), that allows the objects themselves to define the comparison behavior, so you could do: class Foo { function __compare($right) { // logic here } } $left = new Foo; $right = new Foo; $left <=> $right; // Same as $left->__compare($right);

Pierre Joye

12 years ago
On Feb 14, 2014 1:04 AM, "Davey Shafik" <davey@php.net> wrote:
> > On 2/13/14, 12:14 PM, Pierre Joye wrote: >>
> So, this behavior can definitely be changed — preserving the current
behavior of == for the 0 value, and then we can go two different ways for 1/-1: Btw, I forgot to mention that for equality comparisons, we have the instance hash function, which was created exactly for that.

Davey

12 years ago
On 2/13/14, 2:00 PM, Pierre Joye wrote:
> On Feb 14, 2014 1:04 AM, "Davey Shafik" <davey@php.net> wrote: >> >> On 2/13/14, 12:14 PM, Pierre Joye wrote: >>> > >> So, this behavior can definitely be changed — preserving the current > behavior of == for the 0 value, and then we can go two different ways for > 1/-1: > > Btw, I forgot to mention that for equality comparisons, we have the > instance hash function, which was created exactly for that. >
Right, that's what I mean by preserving the behavior of ==

Julien Pauli

12 years ago
On Thu, Feb 13, 2014 at 7:04 PM, Davey Shafik <davey@php.net> wrote:
> On 2/13/14, 12:14 PM, Pierre Joye wrote: >> >> Hi David, >> >> Thanks for this proposal. >> >> On Feb 13, 2014 10:30 PM, "Davey Shafik" <davey@php.net> wrote: >>> >>> >>> On 2/13/14, 2:19 AM, Christian Stoller wrote: >>>> >>>> >>>> Davey Shafik <davey@php.net> wrote: >>>>> >>>>> >>>>> This adds a new operator "(expr) <=> (expr)" that returns 0 if both >>>>> operands are equal, 1 if the left is greater, and -1 if the right is >>>>> greater. >>>>> >>>>> It works with all types (just as well as <, <=, >=, > work) and is >>>>> great >>>>> for usort() callbacks for example. >>>>> >>>> >>>> Why not using `$a - $b` instead of `$a <=> $b`? >>>> >>>> >>>> Simon J Welsh <simon@simon.geek.nz> wrote: >>>>> >>>>> >>>>> The only real case I see for this is to save some boilerplate when >>>>> dealing with arrays. Strings have strcmp(), numbers have subtraction >>>>> And when you're sorting objects, you probably want to be doing >>>>> the comparison on some string/numeric property. >>>>> >>>> >>>> Agreed! It would make more sense to write a comparison function for >> >> arrays/objects. >>>> >>>> >>>> >>>> Best regards >>>> Christian >>>> >>> >>> This operator DOES work on arrays/objects. The fact it also works on >> >> scalar values is a bonus if that's how you want to look at it :P >> >> This new operator doea not look too useful to me but here is one comment >> about objects handling: >> >> It compares only values, seems to be the only solution but the actual >> usage >> for that is rather inexistent as it compares apples and pears, or am I >> missing something? >> >> Cheers, >> Pierre >> > > So, this behavior can definitely be changed -- preserving the current > behavior of == for the 0 value, and then we can go two different ways for > 1/-1: > > - Compare only like-for-like keys, ignoring extra keys > - Compare like-for-like keys, and count the number of additional keys are > being great. So: if they match on all common keys, but left has 3 additional > keys, and right has 4, right is greater than left. > > It's definitely tough to get the semantics right. But: the behavior is also > currently identical to $obj <= $obj2, etc. I felt that consistency was most > important. > > The logical next step with this operator is to add a "Comparable" > "interface" like ruby (not saying it has to be an interface, magic method > also works), that allows the objects themselves to define the comparison > behavior, so you could do: > > class Foo { > function __compare($right) { > // logic here > } > } > > $left = new Foo; > $right = new Foo; > > $left <=> $right; // Same as $left->__compare($right);
Please, don't. Comparable has already been discussed many times, and has its own RFC and topic. https://wiki.php.net/rfc/comparable Don't mix things. Comparable is another idea than adding a new operator. Julien

Christian Stoller

12 years ago
>> >> Why not using `$a - $b` instead of `$a <=> $b`? >> >> >> Simon J Welsh <simon@simon.geek.nz> wrote: >>> The only real case I see for this is to save some boilerplate when >>> dealing with arrays. Strings have strcmp(), numbers have subtraction >>> And when you’re sorting objects, you probably want to be doing >>> the comparison on some string/numeric property. >>> >> >> Agreed! It would make more sense to write a comparison function for arrays/objects. >> >> >> Best regards >> Christian >> > > This operator DOES work on arrays/objects. The fact it also works on > scalar values is a bonus if that's how you want to look at it :P > > - Davey >
That's why I said, it would make more sense to add a new function for comparing arrays and objects. Why adding a new comparison operator if we could achieve the same with one or two additional functions? And I am not sure, if this is not already possible nowadays. For arrays you could do: `array_sum($array1) - array_sum($array2)` And for objects you can define a "sum" method on your objects or a trait e.g. trait SummableTrait { public function sum() { $sum = 0; foreach (get_object_vars($this) as $value) { $sum += $value; } return $sum; } } You only have to use this trait in your classes and then you can do: `$object1->sum() - $object2->sum()` Et voilà :-) Christian

Nikita

12 years ago
On Fri, 14 Feb 2014 11:18:53 +0400, Christian Stoller <stoller@leonex.de> wrote:
>>> >>> Why not using `$a - $b` instead of `$a <=> $b`? >>> >>> >>> Simon J Welsh <simon@simon.geek.nz> wrote: >>>> The only real case I see for this is to save some boilerplate when >>>> dealing with arrays. Strings have strcmp(), numbers have subtraction >>>> And when you’re sorting objects, you probably want to be doing >>>> the comparison on some string/numeric property. >>>> >>> >>> Agreed! It would make more sense to write a comparison function for >>> arrays/objects. >>> >>> >>> Best regards >>> Christian >>> >> >> This operator DOES work on arrays/objects. The fact it also works on >> scalar values is a bonus if that's how you want to look at it :P >> >> - Davey >> > > That's why I said, it would make more sense to add a new function for > comparing arrays and objects. > Why adding a new comparison operator if we could achieve the same with > one or two additional functions? > > And I am not sure, if this is not already possible nowadays. > > For arrays you could do: `array_sum($array1) - array_sum($array2)` > > And for objects you can define a "sum" method on your objects or a trait > e.g. > > trait SummableTrait { > public function sum() { > $sum = 0; > foreach (get_object_vars($this) as $value) { > $sum += $value; > } > return $sum; > } > } > > You only have to use this trait in your classes and then you can do: > `$object1->sum() - $object2->sum()` > > Et voilà :-) > > Christian
Hi, DateTime is the problem here

Jordi Boggiano

12 years ago
On 13/02/2014 04:58, Davey Shafik wrote:
> It works with all types (just as well as <, <=, >=, > work) and is great > for usort() callbacks for example. > > I'd love to get this into 5.6, not sure if we hit feature freeze yet. > Also, not sure if it needs 2/3 majority, but assumed so as pow did? > > Thoughts?
I like shorter sort callbacks, but I think a function taking in "any" data type would be more effective since you could in some cases even shorten it to this: usort($arr, 'magic_compare'); Don't take the name at face value though ;) Cheers
-- Jordi Boggiano @seldaek - http://nelm.io/jordi

Ivan Enderlin @ Hoa

12 years ago
On 13/02/2014 04:58, Davey Shafik wrote:
> Hey folks,
Hello Davey :-), Thanks for the proposal.
> I've written up an RFC/Patch to gauge interest and get feedback on the > addition of a combined comparison (aka: spaceship) operator. > > You can see the RFC at: > https://wiki.php.net/rfc/combined-comparison-operator > > This adds a new operator "(expr) <=> (expr)" that returns 0 if both > operands are equal, 1 if the left is greater, and -1 if the right is > greater. > > It works with all types (just as well as <, <=, >=, > work) and is > great for usort() callbacks for example.
Am I the only one who think that `<=>` is already a Mathematical operator standing for the “equivalence”? PHP already uses `=>` as a key/value matching operator for pairs in an array, whereas in Math., it is the “implies” operator. Right, we may still introduce the `==>` later. But I can't see `<=>` becoming `<==>` or even `<===>`. Moreover, as Jordi and others have suggested, a simple PHP function will do the job, and much better. A -1/0/1 result depends on the compared values and the interpretation of these latters: do we compare the number of pairs in an array, just the keys, just the values, do we also compare the type…? To much context for a single unambiguous operator. One or more dedicated functions (one per type maybe) is a more realistic way in my opinion. Thoughts? Cheers :-).
-- Ivan Enderlin Developer of Hoa http://hoa-project.net/ PhD. student at DISC/Femto-ST (Vesontio) and INRIA (Cassis) http://disc.univ-fcomte.fr/ and http://www.inria.fr/ Member of HTML and WebApps Working Group of W3C http://w3.org/

Rowan Collins

12 years ago
Davey Shafik wrote (on 13/02/2014):
> I'd love to get this into 5.6, not sure if we hit feature freeze yet.
I believe the decision was that to be part of PHP 5.6, the RFC needed to have been introduced before the first alpha, and voting concluded before the first beta. PHP 5.6 Alpha 2 was released yesterday, so no new RFCs should be accepted under that rule. Regards,
-- Rowan Collins [IMSoP]