rfc:comparable

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
rfc:comparable [2010/09/30 13:40] – Bah. Add a title. aharveyrfc:comparable [2017/09/22 13:28] (current) – external edit 127.0.0.1
Line 1: Line 1:
 ====== Request for Comments: Comparable ====== ====== Request for Comments: Comparable ======
-  * Version: 1.0 +  * Version: 7.0 
-  * Date: 2010-09-30+  * Date: 2010-09-30, updated 2015-02-19
   * Author: Adam Harvey <aharvey@php.net>   * Author: Adam Harvey <aharvey@php.net>
   * Status: Under Discussion   * Status: Under Discussion
Line 7: Line 7:
  
  
-This RFC offers a Comparable interface which can be used to implement userspace ordering of objects.+This RFC offers a Comparable interface which can be used to implement userspace comparison of objects to other values.
  
 ===== Introduction ===== ===== Introduction =====
  
-Many other languages offer the ability to provide a method on a class which will be used when instances of that class are compared via comparison or equality operators. For example, Java provides the [[http://download-llnw.oracle.com/javase/6/docs/api/java/lang/Comparable.html|Comparable]] interface, while Python provides the [[http://docs.python.org/reference/datamodel.html#object.__cmp__|__cmp__]] magic method.+Many other languages offer the ability to provide a method on a class which will be used when instances of that class are compared via comparison or equality operators. For example, Java provides the [[http://docs.oracle.com/javase/7/docs/api/java/lang/Comparable.html|Comparable]] interface, while Python provides the [[http://docs.python.org/reference/datamodel.html#object.__cmp__|__cmp__]] magic method
 + 
 +The need for this has only increased as time has gone past, and particularly with the recent implementation of the spaceship operator.
  
 ===== Interface ===== ===== Interface =====
Line 20: Line 22:
 <?php <?php
 interface Comparable { interface Comparable {
-    public function compareTo($o);+    public function compareTo($other);
 } }
 ?> ?>
 </code> </code>
 +
 +This interface intentionally allows variables of any type to be passed to compareTo(): there are use cases where users may want to compare objects to non-object values, such as money and bigint types, where you may want to compare the object to a numeric value.
  
 ===== Sample Code ===== ===== Sample Code =====
Line 71: Line 75:
 ===== Implementation ===== ===== Implementation =====
  
-The patch below implements the Comparable interface within SPL in the same manner as the Countable interface. The changes to the Zend Engine are limited to the zend_operators.c file, and merely involve extending the zend_compare_objects() function to check if the first object implements the Countable interface, and if so, to call the compareTo() method, and updating compare_function() to call zend_compare_objects() when appropriate. Comparison cases not involving objects are unaffected, as are builds without SPL.+The PR linked below implements the Comparable interface by providing a new standard object handler for the compare object handler which checks if the object implements Comparable, and if so, calls the compareTo() method. 
 + 
 +The only change to compare_function() is to ensure that the compare handler is called for the IS_NULL/IS_OBJECT pairs (which probably should have happened anyway), and to allow the compare_objects handler to be used if compare fails. 
 + 
 +===== FAQ ===== 
 + 
 +=== Is only $a checked for Comparable or also $b? === 
 + 
 +Both $a and $b are checked. 
 + 
 +=== How it is ensured that if $a < $b then $b > $a? === 
 + 
 +That's up to the userspace developer to get right when they're implementing their compareTo method. I expect the manual would have a dire warning about the possible consequences of not making them equivalent. 
 + 
 +=== Would sorting work with it? === 
 + 
 +Yes. 
 + 
 +=== If both $a and $b are objects with different compare functions, how it is determined whose function is used? Note that operators like == are assumed to be commutative, and less/more operators are assumed to be commutative in pairslike above. === 
 + 
 +The left operand wins, so $a. 
 + 
 +=== What if the objects are not of the same class? What if one is of a subclass of the other? Is equality not symmetric? === 
 + 
 +Equality is symmetric to the extent that $a->compareTo($b) should return the inverse of $b->compareTo($a). Equality is not required to be symmetric in terms of both objects sharing the same compareTo() method, and comparisons across different class hierarchies are explicitly allowed. 
 + 
 +=== How does this interact with 'get' and 'cast_object'/'__tostring'? === 
 + 
 +The tests for whether the operands implement Comparable occur before any potential calls to get and cast_object. 
 + 
 +=== How does this interact with the compare_objects handler? === 
 + 
 +This will take precedence over a compare_objects handler. This is consistent with the current compare_function() implementation, which calls the compare handler first. 
 + 
 +In practice, I think it's unlikely that an internal class (or a class extending such an internal classwith a compare_objects handler would also implement Comparable. 
 + 
 +===== Concerns ===== 
 + 
 +I'll attempt to summarise the key arguments against this below. Please feel free to edit this if you don't feel your position is accurately represented; I'm trying to be impartial, but obviously I also want to see this succeed. 
 + 
 +  * It's operator overloading; something PHP has historically avoided as a design choice. 
 +  * Comparison of objects with non-objects may become confusing, particularly if scalar casting is added to the mix. 
 +  * Comparison of objects with objects of a different class may be confusing or ill-defined. 
 +  * Why we use interface instead of magic method. Comparable is not reserved currently, but methods started with __ are always reserved. 
 + 
 +===== Alternative Approaches ===== 
 + 
 +=== Traits === 
 + 
 +Stas suggests the following as an alternative to overloading the operator: 
 + 
 +>As a side noteif we have traits we might instead think of having Comparable trait or interface or both, which would declare having compareTo() standard feature (as Java does) without messing with the engine and overloading operators. Surely, it would be more verbose, but that might be a good thing. 
 + 
 +===== Patches ===== 
 + 
 +  * PR against master: [[https://github.com/php/php-src/pull/1097]] 
 +  * Obsolete v1.1 patch against 5.4: [[http://www.adamharvey.name/patches/comparable-v2.diff.txt]] 
 +  * Obsolete v1.0 patch against 5.4: [[http://www.adamharvey.name/patches/comparable.diff.txt]]
  
-===== Patch =====+===== Changelog =====
  
-[[http://www.adamharvey.name/patches/comparable.diff.txt]]+  * 2015-02-19Reanimated RFC; developed new patch that uses the compare handler instead of heavily changing compare_function(). 
 +  * 2010-10-01: Revised patch to remove SPL dependency; added a few questions and answers from the mailing list and a list of concerns raised. 
 +  * 2010-09-30: Initial proposal.
rfc/comparable.1285854052.txt.gz · Last modified: 2017/09/22 13:28 (external edit)