rfc:union_types

Differences

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

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
Next revision Both sides next revision
rfc:union_types [2016/06/02 18:37]
bwoebi
rfc:union_types [2016/06/14 14:44]
levim
Line 1: Line 1:
 ====== PHP RFC: Union Types ====== ====== PHP RFC: Union Types ======
-  * Version: 1.0+  * Version: 1.1
   * Date: 2015-02-14   * Date: 2015-02-14
   * Author: Levi Morrison <levim@php.net>, Bob Weinand <bobwei9@hotmail.com>   * Author: Levi Morrison <levim@php.net>, Bob Weinand <bobwei9@hotmail.com>
-  * Status: Under Discussion+  * Status: Vote
   * First Published at: http://wiki.php.net/rfc/union_types   * First Published at: http://wiki.php.net/rfc/union_types
  
 ===== Introduction ===== ===== Introduction =====
-In PHP using "type hints" to define either the allowed parameter types for a functionor the return type of a function, performs two useful roles:+PHP has [[http://php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration|type declarations]] which can be associated with function parameters or return values. These declarations perform two useful roles:
  
-  * Using types allows the PHP engine to enforce the correct type of variable passed toor returned froma function. +  * They allow the PHP engine to enforce the correct type of variable passed to or returned from a function. 
-  * Using types makes it easy to reason about what types need to be passed toor can be returned from a function. This makes it easier for both humansand static code analysis toolsto determine about whether code is correct or not.+  * They make it easier to reason about what types need to be passed to or can be returned from a function. Both humans and static code analysis tools can use this information to help determine the correctness of the code.
  
-For a lot of functions in PHPeach parameter will only be one type. Similarly, for the majority of functionsthe return value of a function, will only ever be of one type.+For a lot of functions in PHP each parameter will only be one type. Similarly, for the majority of functions the return value will only ever be of one type.
  
-However, for a significant number of functions, the acceptable parametersor the possible return valuescan be of more than one type. For example consider the ''stripos'' function where the return value varies based on:+However, for a significant number of functions, the acceptable parameters or the possible return values can be of more than one type. For example consider the ''stripos'' function where the return value varies based on:
  
   * if the needle exists it returns an integer.   * if the needle exists it returns an integer.
Line 21: Line 21:
 In the documentation on php.net, the two possible return types are documented as ''mixed'' - however this does not actually document what the possible return types are, only that there is more than one possible type returned. In the documentation on php.net, the two possible return types are documented as ''mixed'' - however this does not actually document what the possible return types are, only that there is more than one possible type returned.
  
-Currently in userland codewhen a parameter for a function can be one of multiple but limited set of types, or the return value from a function can be one of multiple but limited set of types, there can be no type information supplied, and so it is not possible for the PHP engine to enforce any types passed to/from that function, and it is not easy for people using that function to reason about the types passed to/returned from that function.+Currently in userland code when a parameter for a function can be one of multiple types, or the return value from a function can be one of multiple types, there can be no type information supplied. It is not possible for the PHP engine to enforce any types passed to/from these functions and similarly it is not easy for people using these functions to reason about the types passed to/returned from these functions.
  
-This RFC seeks to address this limitation.+This RFC seeks to address these limitations.
  
-==== Proposal ====+===== Proposal =====
 This RFC proposes the ability to define multiple possible types for parameter and return types. To define a 'union type' a single vertical bar (OR) is placed between types e.g. ''int|bool'' represents the union type of either integer or boolean. For these 'union types' a value passes the type check if the value would pass any one of the types in the union.  This RFC proposes the ability to define multiple possible types for parameter and return types. To define a 'union type' a single vertical bar (OR) is placed between types e.g. ''int|bool'' represents the union type of either integer or boolean. For these 'union types' a value passes the type check if the value would pass any one of the types in the union. 
  
Line 32: Line 32:
 There can be more than two types in the union. There can be more than two types in the union.
  
-=== Parameter type examples ===+==== Parameter type examples ====
 A function that requires either a string or an array is passed to it as the parameter: A function that requires either a string or an array is passed to it as the parameter:
 <PHP> <PHP>
Line 59: Line 59:
 For this example, it is clear to both static analysis tools and humans that passing anything other than a ParameterGenerator object or a string to this function, would be an error.  For this example, it is clear to both static analysis tools and humans that passing anything other than a ParameterGenerator object or a string to this function, would be an error. 
  
-=== Return type example ===+==== Return type example ====
 A userland definition of ''stripos'' function: A userland definition of ''stripos'' function:
  
Line 123: Line 123:
 Otherwise PHP's casting rules are applied in an order to be as lossless as possible. PHP's weak-type casting rules are complex, which leads to a seemingly complex set of rules for casting types, however these rules are not an invention of this proposal. This RFC applies PHP casting rules in a sane way to convert a value to a type accepted by the union whenever possible. Otherwise PHP's casting rules are applied in an order to be as lossless as possible. PHP's weak-type casting rules are complex, which leads to a seemingly complex set of rules for casting types, however these rules are not an invention of this proposal. This RFC applies PHP casting rules in a sane way to convert a value to a type accepted by the union whenever possible.
  
-^ Passed type ^ Argument type #1 ^ #2 ^ #3 ^ #4 +^ Passed type ^ Union type #1 ^ #2 ^ #3 ^ 
-| object | string (''<nowiki>__toString()</nowiki>''| - | - | - | +| object | string (''<nowiki>__toString()</nowiki>'') | - | - | 
-| boolean | int | float | string | - +| boolean | int | float | string | 
-| int | float | string | boolean | - +| int | float| string | boolean | 
-| float | int (exact match) | string | int | boolean | +| float | string | int | boolean | 
-| string | int/float<sup>†</sup> | boolean | - | - | +| string | int/float<sup>†</sup> | boolean | - | 
-<sup>†</sup> only if actually numeric, the result of ''$str + 0''\\+* While string is more lossless than float for big values, we have to match behavior with strict types enabled here\\ 
 +<sup>†</sup> only if ''is_numeric()'' would return true\\
 Respecting the order, for each type check if it is available in the union, else throw a ''TypeError'' if none is available. Respecting the order, for each type check if it is available in the union, else throw a ''TypeError'' if none is available.
 +
 +== Problems with left-to-right ==
 +Left-to-right conversion has been proposed multiple times. But this is not a viable solution for the following reasons:
 +  * (string|float) would convert to a string if passed an integer, which would be inconsistent with strict types converting it to a float. This type of inconsistency must be avoided.
 +  * Also, in strict left-to-right, exact matches would still be cast to the first type (from the left) which they can be cast to. This would again, be inconsistent with strict types enabled.
 +  * Ultimately, (float|int) would, even in strict types mode, lead to a conversion to float in any case upon passing integer; this is very counterintuitive.
 +
 +It might be possible to exempt exact matches, but then we have yet another rule and still the first problem in the list above. At which point it just is much simpler to have well-defined conversion order depending on the passed type.
  
 ==== Variance ==== ==== Variance ====
Line 147: Line 156:
  
 ==== Reflection ==== ==== Reflection ====
-This RFC proposes the addition of <php>ReflectionType::isUnion(): bool;</php> to check whether the type is an union type.+This RFC proposes the addition of a class <php>ReflectionUnionType</php> inheriting from <php>ReflectionType</php> with a single method <php>ReflectionUnionType::getTypes(): array<ReflectionType>;</php> to get the reflection classes of the individual types in the union.
  
-ReflectionType::__toString() will now provide a full union type as string; e.g. ''"int | float | NumberObject"''.+''ReflectionUnionType::__toString()'' will now provide a full union type as string; e.g. ''"int | float | NumberObject"''.
  
 ===== Proposed PHP Version(s) ===== ===== Proposed PHP Version(s) =====
 This RFC targets PHP version 7.1. This RFC targets PHP version 7.1.
  
-===== Proposed Voting Choices =====+===== Vote =====
 This RFC requires that two-thirds of voters vote in favor of the RFC to pass. This RFC requires that two-thirds of voters vote in favor of the RFC to pass.
 +
 +<doodle title="Merge union types" auth="bwoebi" voteType="single" closed="false">
 +   * Yes
 +   * No
 +</doodle>
  
 Additionally, there are two 50%+1 votes: Additionally, there are two 50%+1 votes:
  
-  * on replacing ''?QuestionMarkNullables'' by ''union | null'', +<doodle title="Replace ?QuestionMarkNullables by union | null" auth="bwoebi" voteType="single" closed="false"> 
-  and the true/false types (for unions only).+   Yes 
 +   * No 
 +</doodle> 
 +​ 
 +<doodle title="Include true/false types" auth="bwoebi" voteType="single" closed="false"> 
 +   * Yes 
 +   * No 
 +</doodle> 
 + 
 +The vote started 14th June 2016 and will end 23th June 2016.
  
 ===== Patches and Tests ===== ===== Patches and Tests =====
rfc/union_types.txt · Last modified: 2017/09/22 13:28 (external edit)