rfc:operator_overloading_gmp

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:operator_overloading_gmp [2013/05/17 18:37] – Update overloading proposal for compare addition nikicrfc:operator_overloading_gmp [2017/09/22 13:28] (current) – external edit 127.0.0.1
Line 4: Line 4:
   * Date: 2013-05-12   * Date: 2013-05-12
   * Author: Nikita Popov <nikic@php.net>   * Author: Nikita Popov <nikic@php.net>
-  * Status: Draft+  * Status: Implemented in PHP 5.6
   * Patch: https://github.com/php/php-src/pull/342   * Patch: https://github.com/php/php-src/pull/342
-  * Target version: PHP 5.6 (or whatever the next one is) 
  
 ===== Introduction ===== ===== Introduction =====
Line 13: Line 12:
  
 ===== Proposal A: Operator overloading ===== ===== Proposal A: Operator overloading =====
 +
 +Note: This proposal is only about **internal** operator overloading and **not** about userland overloading.
  
 ==== Why operator overloading? ==== ==== Why operator overloading? ====
Line 81: Line 82:
   * Unsigned arithmetic and arithmetic on other integral types PHP does not support (e.g. cross platform 64bit integers)   * Unsigned arithmetic and arithmetic on other integral types PHP does not support (e.g. cross platform 64bit integers)
   * Vector and matrix calculations   * Vector and matrix calculations
-  * (Misuse for DSLs)+ 
 +Due to potential pitfalls of misusing operator overloading known from other languages (most notably C++), the use of this new feature should be limited to cases where there are clear definitions to the behavior of all overloaded operators. The application of this feature should be for mathematical use cases only (as noted above), and not 'creative' applications such as changing the white balance of a picture by incrementing or decrementing the picture object.
  
 ==== Technical proposal ==== ==== Technical proposal ====
Line 137: Line 139:
 Here ''result'' is the target zval, ''op1'' the first operand and ''op2'' the second operand. The ''result'' zval has to be set to one of the longs ''-1'' (indicating "greater than"), ''0'' (indicating "equal") or ''-1'' (indicating "less than"). The return value can either be ''SUCCESS'' or ''FAILURE'', which indicate whether the comparison was successful. This return value will be the return value of ''compare_function''. Here ''result'' is the target zval, ''op1'' the first operand and ''op2'' the second operand. The ''result'' zval has to be set to one of the longs ''-1'' (indicating "greater than"), ''0'' (indicating "equal") or ''-1'' (indicating "less than"). The return value can either be ''SUCCESS'' or ''FAILURE'', which indicate whether the comparison was successful. This return value will be the return value of ''compare_function''.
  
-The ''compare'' handler is called for the ''<'', ''%%<=%%'', ''=='', ''%%=>%%'' and ''>'' operators and any other code using ''compare_function'' (e.g. sorting). The operators ''==='' and ''!=='' are explicitly **not** supported, as they have clearly defined semantics (same object handle) and I see now reason to break this.+The ''compare'' handler is called for the ''<'', ''%%<=%%'', ''=='', ''!='', ''>='' and ''>'' operators and any other code using ''compare_function'' (e.g. sorting). The operators ''==='' and ''!=='' are explicitly **not** supported, as they have clearly defined semantics (same object handle) and I see now reason to break this.
  
 The difference between the ''compare'' handler and the already existing ''compare_objects'' handler is that ''compare'' is called for **all** comparisons involving an object with a ''compare'' handler, whereas ''compare_objects'' is only called if both operands are objects and have the same ''compare_objects'' handler. Thus ''compare_objects'' can not be used to implement comparisons like ''$gmp == 0''. A ''compare'' handler always takes precedence over a ''compare_objects'' handler. The difference between the ''compare'' handler and the already existing ''compare_objects'' handler is that ''compare'' is called for **all** comparisons involving an object with a ''compare'' handler, whereas ''compare_objects'' is only called if both operands are objects and have the same ''compare_objects'' handler. Thus ''compare_objects'' can not be used to implement comparisons like ''$gmp == 0''. A ''compare'' handler always takes precedence over a ''compare_objects'' handler.
Line 152: Line 154:
   * Bad reporting on leaks. During the port I found that many functions leak resources, especially in error conditions.   * Bad reporting on leaks. During the port I found that many functions leak resources, especially in error conditions.
  
-This RFC proposes to make GMP use objects (of type ''GMP'') as the underlying structure. Using this new structure, the RFC implements support for serialization, casting, dumping and overloaded operators. +This RFC proposes to make GMP use objects (of type ''GMP'') as the underlying structure. Using this new structure, the RFC implements support for casting, dumping, serialization, cloning and overloaded operators. In the following there are examples for the new behaviors:
- +
-In the following there are examples for some of the new behaviors:+
  
 === Casting === === Casting ===
Line 172: Line 172:
 var_dump($s = serialize($n)); var_dump($s = serialize($n));
 var_dump(unserialize($s)); var_dump(unserialize($s));
 +
 // outputs // outputs
 +
 object(GMP)#%d (1) { object(GMP)#%d (1) {
   ["num"]=>   ["num"]=>
Line 181: Line 183:
   ["num"]=>   ["num"]=>
   string(2) "42"   string(2) "42"
 +}
 +</code>
 +
 +=== Cloning ===
 +
 +<code php>
 +$a = gmp_init(3);
 +$b = clone $a;
 +gmp_clrbit($a, 0);
 +var_dump($a, $b);
 +
 +// Output: (Note that $b is still 3)
 +
 +object(GMP)#1 (1) {
 +  ["num"]=>
 +  string(1) "2"
 +}
 +object(GMP)#2 (1) {
 +  ["num"]=>
 +  string(1) "3"
 } }
 </code> </code>
Line 193: Line 215:
 var_dump($a + 17); var_dump($a + 17);
 var_dump(42 + $b); var_dump(42 + $b);
 +
 // Outputs the following 3 times: // Outputs the following 3 times:
 +
 object(GMP)#%d (1) { object(GMP)#%d (1) {
   ["num"]=>   ["num"]=>
Line 200: Line 224:
 </code> </code>
  
-The following operators are supported: ''+'', ''-'', ''*'', ''/'', ''%'', ''|'', ''&'', ''^'', ''~'', ''==''''!='', ''<'', ''%%<=%%'', ''>'', ''>=''. The operators ''%%<<%%''''%%>>%%'' are not yet supported, but support is plannedAll operators work with two GMP values or one GMP value and one GMP-coercible value (e.gstrings and integers).+The following operators are supported: ''+'', ''-'', ''*'', ''/'', ''%'', ''|'', ''&'', ''^'', ''~'', ''%%<<%%'' and ''%%>>%%''. All operators work with two GMP values or one GMP value and one GMP-coercible value (e.g. strings and integers). 
 + 
 +=== Overloaded operators: Comparison === 
 + 
 +<code php> 
 +$a = gmp_init(42); 
 +var_dump($a == 42  $a == 17,    $a < 40,     $a < 100); 
 +//       bool(true), bool(false), bool(false), bool(true) 
 +</code> 
 + 
 +Comparison is supported via the ''=='', ''!='', ''<'', ''>''''%%<=%%'' and ''>='' operatorsSorting and other comparison-based operations work as well: 
 + 
 +<code php> 
 +$arr = [gmp_init(0), -3, gmp_init(2), 1]; 
 +sort($arr); 
 +var_dump($arr); 
 + 
 +// Outputs 
 + 
 +array(4) { 
 +  [0]=> 
 +  int(-3) 
 +  [1]=> 
 +  object(GMP)#1 (1) { 
 +    ["num"]=> 
 +    string(1) "0" 
 +  } 
 +  [2]=> 
 +  int(1) 
 +  [3]=> 
 +  object(GMP)#2 (1) { 
 +    ["num"]=> 
 +    string(1) "2" 
 +  } 
 +
 +</code> 
 + 
 +=== Other minor changes === 
 + 
 +During the refactoring of the implementation a few additional, small changes were done: 
 + 
 +  * If you pass a GMP instance to ''gmp_fact'' you will get the factorial of the GMP number (and not the factorial of the resource ID). 
 +  * Previously some functions like ''gmp_mod'' returned a long result if the second argument was longThis inconsistent and partially buggy behavior is no longer present and a GMP instance is always returned. As the GMP instance is castable to a long this does not break compatibility with scripts relying on the old behavior. 
 +  * Due to the previous change ''gmp_div_r'' no longer returns an incorrect result in some rounding modes. 
 +  * If you pass an invalid rounding mode to a function, you will now get a warning.
  
 ===== Backward Incompatible Changes ===== ===== Backward Incompatible Changes =====
Line 216: Line 284:
 <code> <code>
                      NEW    OLD                      NEW    OLD
-a) gmp_add($a, $b)   1.16   1.25 +a) gmp_add($a, $b)   1.07   1.25 
-b) gmp_add($a, 17)   1.08   1.21 +b) gmp_add($a, 17)   1.02   1.21 
-c) gmp_add(42, $b)   1.29   1.84 +c) gmp_add(42, $b)   1.20   1.84 
-d) $a + $b           0.83   ---+d) $a + $b           0.76   ---
 </code> </code>
  
Line 227: Line 295:
  
 The pull request for this RFC can be found here: https://github.com/php/php-src/pull/342 The pull request for this RFC can be found here: https://github.com/php/php-src/pull/342
 +
 +===== Vote =====
 +
 +The vote started on 10.06.2013 and ended on 17.06.2013. Both proposals are accepted.
 +
 +<doodle title="Should these changes be applied for PHP 5.6?" auth="nikic" voteType="multi" closed="true">
 +   * Internal operator overloading
 +   * GMP changes
 +   * None
 +</doodle>
  
 ===== Previous discussions ===== ===== Previous discussions =====
  
-http://markmail.org/message/y7rq5vcd5ucsbcyb (Note: The patch that is being discussed there is not accessible anymore.)+http://markmail.org/message/y7rq5vcd5ucsbcyb: This is a rather old discussion on userland operator overloading (so not really the same as this). The patch discussed there is no longer accessible.
rfc/operator_overloading_gmp.1368815832.txt.gz · Last modified: 2017/09/22 13:28 (external edit)