rfc:userspace_operator_overloading

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:userspace_operator_overloading [2020/03/05 13:45] jbtronicsrfc:userspace_operator_overloading [2020/04/06 19:31] (current) jbtronics
Line 1: Line 1:
 ====== PHP RFC: Userspace operator overloading ====== ====== PHP RFC: Userspace operator overloading ======
-  * Version: 0.3.2+  * Version: 0.5
   * Date: 2020-02-01   * Date: 2020-02-01
   * Author: Jan Böhmer, jan.h.boehmer@gmx.de   * Author: Jan Böhmer, jan.h.boehmer@gmx.de
-  * Status: Under Discussion +  * Status: Declined 
-  * First Published athttp://wiki.php.net/rfc/userspace_operator_overloading+  * Target VersionPHP 8.0 
 +  * Implementation: https://github.com/php/php-src/pull/5156 
 ===== Introduction ===== ===== Introduction =====
 At the moment expressions like ''$a + $b'' or ''$a * 2'' are only valid if ''$a'' and ''$b'' are scalar types like int or float. However, in many other programming languages like Python, C# or C++ it is possible to overload these operators to use them on classes, to implement custom math (and other) objects. This RFC proposes userspace operator overloading for PHP. At the moment expressions like ''$a + $b'' or ''$a * 2'' are only valid if ''$a'' and ''$b'' are scalar types like int or float. However, in many other programming languages like Python, C# or C++ it is possible to overload these operators to use them on classes, to implement custom math (and other) objects. This RFC proposes userspace operator overloading for PHP.
Line 27: Line 28:
 class Vector3() class Vector3()
 { {
-    // For simple cases type checking can be done by typehints. +    public static function __add($lhs, $rhs) {
-    public static function __add(Vector3 $lhs, Vector3 $rhs) {+
         // Do something with the values and return a non-null value         // Do something with the values and return a non-null value
-        // ... 
     }     }
          
-    public static function __mul($lhs, $rhs) { +    public static function __mul($lhs, $rhs): ?Vector3 
-        // For more complex type checking, the function can return a special const.+        // If the given types are not supported, the function can return a special const.
         //...         //...
         return PHP_OPERAND_TYPES_NOT_SUPPORTED;         return PHP_OPERAND_TYPES_NOT_SUPPORTED;
Line 45: Line 44:
 // Equivalent to $x = Vector3::__add($a, $b) // Equivalent to $x = Vector3::__add($a, $b)
 $x = $a + $b; $x = $a + $b;
-//Equivalent to $y = Vecotr3::__mul(2, $b)+//Equivalent to $y = Vector3::__mul(3, $b)
 $y = 3 * $b; $y = 3 * $b;
 </PHP> </PHP>
Line 51: Line 50:
 By passing both operands to the handler, it can decide between the cases on non-commutative operators (''$a / 2'' vs. ''2 / $a''), which would be more difficult when only the "other" operand (besides ''$this'') is passed. By passing both operands to the handler, it can decide between the cases on non-commutative operators (''$a / 2'' vs. ''2 / $a''), which would be more difficult when only the "other" operand (besides ''$this'') is passed.
  
-The magic function can accept any type, the function has to decide if it can handle the type (and the value). If it can not handle the given type, it has to return the constant ''PHP_OPERAND_TYPES_NOT_SUPPORTED'' (currently just null). Typehints can be used in function signature to signalwhich types are supported.+The magic function can accept any type, the function has to decide if it can handle the type (and the value). If it can not handle the given type, it has to return the constant ''PHP_OPERAND_TYPES_NOT_SUPPORTED'' (currently just null). 
 + 
 +The argument **must not** specify any argument typehints (an error is thrown otherwise), as typehints and occuring type errors would break operator evaluation ([[https://externals.io/message/108788#108993|see discussion]]). 
 + 
 +Handlers **can** specify return typehintsbut note that the return type has to be nullable (as PHP_OPERAND_TYPES_NOT_SUPPORTED has the value null).
  
 ==== Overloadable Operators ==== ==== Overloadable Operators ====
Line 80: Line 83:
 ^ Positive value | ''+ $a'' | interpreted as **''(+1)*$a''**, can be overloaded by implementing %%__mul%% | ^ Positive value | ''+ $a'' | interpreted as **''(+1)*$a''**, can be overloaded by implementing %%__mul%% |
 ^ Shorthand assignment | ''+='', ''*='', ''.='', etc. | ''$a += $b'' is interpreted as ''$a = $a + $b'', can be overloaded by implementing %%__add%% | ^ Shorthand assignment | ''+='', ''*='', ''.='', etc. | ''$a += $b'' is interpreted as ''$a = $a + $b'', can be overloaded by implementing %%__add%% |
-^ Increment | ''$a++'' | interpreted as ''$a = $a + 1'', can be overloaded by implementing %%__add%% | +^ Increment | ''$a++'' (and ''++$a''| interpreted as ''$a = $a + 1'', can be overloaded by implementing %%__add%% | 
-^ Decrement | ''$a--''  | interpreted as ''$a = $a - 1'', can be overloaded by implementing %%__sub%% |+^ Decrement | ''$a%%--%%'' (and ''%%--%%$a'' | interpreted as ''$a = $a - 1'', can be overloaded by implementing %%__sub%% |
  
 === Operators that can not be overloaded === === Operators that can not be overloaded ===
 The following operators can not be overloaded by using this method (neither explicit or implicit): The following operators can not be overloaded by using this method (neither explicit or implicit):
 |                       ^ Operator                                                   | |                       ^ Operator                                                   |
-| Comparision operators | ''<'', ''<='', ''>'', ''=='' etc.       | maybe subject of a future RFC |+| Comparision operators | ''<'', ''%%<=%%'', ''>'', ''=='' etc.       | maybe subject of a future RFC |
 | Assignment operator   | ''='' | | | Assignment operator   | ''='' | |
 | Logic operators        | ''||'', ''!'', ''&&'' | | | Logic operators        | ''||'', ''!'', ''&&'' | |
Line 93: Line 96:
 | Tenary operator       | ''? :'' | | | Tenary operator       | ''? :'' | |
 | Error control operator | ''@'' | | | Error control operator | ''@'' | |
-| Object access operator | ''->'' |  |+| Object access operator | ''%%->%%'' |  |
  
 ==== Evaluation order ==== ==== Evaluation order ====
Line 107: Line 110:
  
 An operand handler can signal that it does not support the given types by returning the const ''PHP_OPERAND_TYPES_NOT_SUPPORTED'' (at the moment null). In this case it is tried to use the handler on the left object. If both handlers do not support the given operand types an error is thrown. An operand handler can signal that it does not support the given types by returning the const ''PHP_OPERAND_TYPES_NOT_SUPPORTED'' (at the moment null). In this case it is tried to use the handler on the left object. If both handlers do not support the given operand types an error is thrown.
- 
-If the operator handler function declares typehints (e.g. ''public static function %%__%%add(Vector3 $lhs, int $rhs)''), the function handler is not called if the operand types do not match the signature, and the other operand's handler is tried to call. 
- 
-Both methods can be combined. 
  
 ==== Error handling ==== ==== Error handling ====
-If an operator is used with an object that does not overload this operator, an NOTICE is triggered, which gives the user a hint about the method that has to be overloaded. For backward compatibility objects, which do not overload the operator, are converted to integer 1 (current behavior).+If an operator is used with an object that does not overload this operator, an NOTICE is triggered (to not break existing code), which gives the user a hint about the method that has to be overloaded. For backward compatibility objects, which do not overload the operator, are converted to integer 1 (current behavior).
  
 If the class overloads the operator, and the magic method do not return a value, an ERROR is triggered. If the class overloads the operator, and the magic method do not return a value, an ERROR is triggered.
  
 If the given operand types are not supported on both objects, an ERROR is thrown. If the given operand types are not supported on both objects, an ERROR is thrown.
 +
 +If the operator handler declares argument type hints or arguments should be passed-by-reference an ERROR is thrown.
  
 ==== Other ==== ==== Other ====
 A user who overloads an operator MUST ensure, that the magic function do not change the existing operand objects, or it will cause undesirable behavior. At the moment there is no way to enforce immutability on objects, so the user is responsible. The documentation should include a warning about this. A user who overloads an operator MUST ensure, that the magic function do not change the existing operand objects, or it will cause undesirable behavior. At the moment there is no way to enforce immutability on objects, so the user is responsible. The documentation should include a warning about this.
- 
  
 ===== Backward Incompatible Changes ===== ===== Backward Incompatible Changes =====
Line 154: Line 154:
  
 ==== Immutable types ==== ==== Immutable types ====
-To ensure that objects can not be changed (which could cause undesirable behavior), immutable objects (see this [[rfc:immutability|old RFC]] could be helpful.+To ensure that objects can not be changed (which could cause undesirable behavior), immutable objects (see this [[rfc:immutability|old RFC]]could be helpful.
  
 ==== Allow overloading of shorthand assignment operators and increment/decrement operators ==== ==== Allow overloading of shorthand assignment operators and increment/decrement operators ====
Line 160: Line 160:
  
 ===== Proposed Voting Choices ===== ===== Proposed Voting Choices =====
-Accept the existing proposed changes for 8.0: yes/no+Add userspace operator overloading as described: yes/no 
 + 
 +===== Vote ===== 
 +Voting started 2020-03-23 and ends 2020-04-06. 
 +<doodle title="Add userspace operator overloading as described?" auth="jbtronics" voteType="single" closed="true"> 
 +   * Yes 
 +   * No 
 +</doodle>
  
 ===== Patches and Tests ===== ===== Patches and Tests =====
-Draft implementation can be found here: https://github.com/php/php-src/pull/5156+Implementation can be found here: https://github.com/php/php-src/pull/5156
  
 ===== References ===== ===== References =====
Line 169: Line 176:
    * [[https://externals.io/message/108300|First email discussion]]    * [[https://externals.io/message/108300|First email discussion]]
    * [[rfc:operator-overloading|Old RFC with an similar propose]]    * [[rfc:operator-overloading|Old RFC with an similar propose]]
 +   * [[https://externals.io/message/108608|Discussion part 1]]
 +   * [[https://externals.io/message/108788|Discussion part 2]]
  
-===== Rejected Features =====+===== Rejectected features ===== 
 +  * Use interfaces instead of magic methods 
 +  * Use type hints to declare supported types (this would introduce some special kind of function overloading)
  
 ===== Changelog ===== ===== Changelog =====
Line 178: Line 189:
   * **0.3.1** Renamed shift handler to ''%%__%%lshift'' and ''%%__%%rshift''   * **0.3.1** Renamed shift handler to ''%%__%%lshift'' and ''%%__%%rshift''
   * **0.3.2** Renamed some functions handler. Added tables which operators can be overloaded indirectly and which can not be overloaded at all.   * **0.3.2** Renamed some functions handler. Added tables which operators can be overloaded indirectly and which can not be overloaded at all.
 +  * **0.4** Removed type support decisions based on typehints, because this introduces some kind of function overloading.
 +  * **0.5** Disallow argument typehints in operator handlers.
rfc/userspace_operator_overloading.1583415956.txt.gz · Last modified: 2020/03/05 13:45 by jbtronics