rfc:nullable_intersection_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
rfc:nullable_intersection_types [2021/07/23 09:30]
nicolasgrekas
rfc:nullable_intersection_types [2021/08/29 19:13] (current)
marandall Updated status tag after being declined (announced on ML).
Line 3: Line 3:
   * Date: 2021-07-22   * Date: 2021-07-22
   * Author: Nicolas Grekas, nicolasgrekas@php.net   * Author: Nicolas Grekas, nicolasgrekas@php.net
-  * Status: Draft+  * Status: Declined
   * Implementation: https://github.com/php/php-src/pull/7259   * Implementation: https://github.com/php/php-src/pull/7259
   * First Published at: https://wiki.php.net/rfc/nullable_intersection_types   * First Published at: https://wiki.php.net/rfc/nullable_intersection_types
Line 28: Line 28:
 } }
 </PHP> </PHP>
 +
 +On the reflection side, ''ReflectionIntersectionType::allowsNull()'' will return ''true''/''false'' depending on what the intersection type accepts.
  
 ===== Rationale ===== ===== Rationale =====
-When PHP 7.0 introduced scalar types, it was obvious that the special ''null'' type was missing as a way to declare the empty state of an argument, property, or return value. PHP 7.1 added the "''?foo''" syntax to declare nullability and scalar types gained much broader adoption. This lesson from history tells us that the nullable type is special and very much needed in PHP.+When PHP 7.0 introduced scalar types, it was obvious that the special ''null'' type was missing as a way to declare that ''null'' was a possible return value. PHP 7.1 added the "''?foo''" syntax to declare their nullability. This lesson from history tells us that the nullable type is special and very much needed in PHP.
  
 As for scalars, nullable intersection types would make optional arguments/properties/return-values trivial to implement. It would also make them consistent with the other type declarations. As for scalars, nullable intersection types would make optional arguments/properties/return-values trivial to implement. It would also make them consistent with the other type declarations.
Line 39: Line 41:
  
 For all these reasons, this RFC proposes to make intersection types nullable, and to make them so right away in PHP 8.1. For all these reasons, this RFC proposes to make intersection types nullable, and to make them so right away in PHP 8.1.
 +
 +About reflection, one could imagine a more complex model based on a ''ReflectionIntersectionType'' nested inside a ''ReflectionUnionType''. This RFC proposes to rely on ''ReflectionIntersectionType::allowsNull()'' instead. This is consistent with how ''T|null'' is returned without ''ReflectionUnionType'' wrapper, and is also simpler for userland to deal with.
  
 ===== Future Scope ===== ===== Future Scope =====
Line 48: Line 52:
   * Reflection   * Reflection
  
-From a conceptual pov, nullability is a special form of composite type. Yet, nullability doesn't have these concerns, because the engine already deals will ''null'' in a special way: ''MAYBE_BE_NULL'' is a flag that any type can carry internally, independently from any other type constraints, and reflection provides the ''allowsNull()'' method everywhere needed.+From a conceptual pov, nullability is a special form of composite type. Yet, nullability doesn't have these concerns, because the engine already deals will ''null'' in a special way: ''MAY_BE_NULL'' is a flag that any type can carry internally, independently from any other type constraints, and reflection provides the ''allowsNull()'' method everywhere needed.
  
 This means we don't need (and shouldn't) wait to solve the generic case to solve the nullability case, which is particular anyway. The very benefits to solve the generic case have even not been discussed yet. The possibility exists that we decide that we don't need to solve it. This means we don't need (and shouldn't) wait to solve the generic case to solve the nullability case, which is particular anyway. The very benefits to solve the generic case have even not been discussed yet. The possibility exists that we decide that we don't need to solve it.
Line 64: Line 68:
 Since both possibilities contain several operators ("''?''" and "''&''" / "''|''" and "''&''" respectively), operator precedence should be taken into account to resolve any possible ambiguity when interpreting the type expression. PHP already defines "''|''" as having a lower precedence than the "''&''" operators. This means that "''X&Y|null''" can only be interpreted as "''(X&Y) | null''", which is what we want to express here. Since both possibilities contain several operators ("''?''" and "''&''" / "''|''" and "''&''" respectively), operator precedence should be taken into account to resolve any possible ambiguity when interpreting the type expression. PHP already defines "''|''" as having a lower precedence than the "''&''" operators. This means that "''X&Y|null''" can only be interpreted as "''(X&Y) | null''", which is what we want to express here.
  
-The precedence of the "''?''" type-operator is not defined yet. Looking at the precedence of null-related operators (see [[https://php.net/language.operators.precedence|this table]]), they are all below the "''&''" and "''|''" operators, which is what we need to unambiguously interpret "''?X&Y''" as "''? (X&Y)''". Another consideration related to composite types backs this interpretation up: whatever the nesting level of an hypothetical composite type definition, nullability can always we expressed as a single flag that sits next to the non-null constraints of the type (as the engine does it already.This is because any intersection that contains the ''null'' type is identical to the ''null'' type itself.+The precedence of the "''?''" type-operator is not defined yet. Looking at the precedence of null-related operators (see [[https://php.net/language.operators.precedence|this table]]), they are all below the "''&''" and "''|''" operators, which is what we need to unambiguously interpret "''?X&Y''" as "''? (X&Y)''". Another consideration related to composite types backs this interpretation up: whatever the nesting level of an hypothetical composite type definition, nullability can always we expressed as a single flag that sits next to the non-null constraints of the type. This is because any intersections that contain the ''null'' type are identical to the ''never'' type.
  
 Taking all these elements into account, the preference of the author of this RFC is to define "''?''" as having a lower precedence than any other type-operator, and thus to use the "''?X&Y''" syntax. This reads quickly from left to right as: 1. the type is nullable 2. here are the constraints that apply to any non-null values. Taking all these elements into account, the preference of the author of this RFC is to define "''?''" as having a lower precedence than any other type-operator, and thus to use the "''?X&Y''" syntax. This reads quickly from left to right as: 1. the type is nullable 2. here are the constraints that apply to any non-null values.
Line 84: Line 88:
 </PHP> </PHP>
  
-That being said and because it's kinda hard to gather a broad consensus on syntax choices, this RFC proposes various possible options for the community to decide. Using ''null|X&Y'' is not offered as an option because it would be "over-delivering syntax that hasn't been entirely thought through" (using sgolemon's words) and that should be introduced by a potential future RFC that would extend to composite types.+That being said and because it's kinda hard to gather a broad consensus on syntax choices, this RFC proposes various possible options for the community to decide. Using "''null|X&Y''is not offered as an option because it would be "over-delivering syntax that hasn't been entirely thought through" (using sgolemon's words) and that should be introduced by a potential future RFC that would extend to composite types.
  
 It is also the author's opinion that introducing brackets would be over-delivering syntax. Precedence rules + "nullability is a flag" arguments make them unnecessary. Not using brackets also eases with visual reading, to quickly spot eg the end of the signature of a function declaration. This is still offered as a possible vote option. It is also the author's opinion that introducing brackets would be over-delivering syntax. Precedence rules + "nullability is a flag" arguments make them unnecessary. Not using brackets also eases with visual reading, to quickly spot eg the end of the signature of a function declaration. This is still offered as a possible vote option.
Line 92: Line 96:
  
 ===== Proposed Voting Choices ===== ===== Proposed Voting Choices =====
-As per the voting RFC, the first question requires a 2/3 majority for this proposal to be accepted:+As per the voting RFC, the first question requires a 2/3 majority for this proposal to be accepted. The other choices require simple majority.
  
   * Make intersection types nullable: yes / no   * Make intersection types nullable: yes / no
   * Preferred syntax: "?" prefix / "|null" suffix   * Preferred syntax: "?" prefix / "|null" suffix
-  * If "?" wins, brackets should be: mandatory "?(Y&Y)" / not needed "?X&Y/ allow both styles +  * Intersections should be: without brackets around / with brackets around / allow both styles 
-  If "|null" wins, brackets should be: mandatory "(Y&Y)|null/ not needed "X&Y|nullallow both styles+ 
 +===== Vote ===== 
 + 
 +Voting starts 2021-08-13 09:30 UTC and ends 2021-08-27 17:00 UTC. 
 + 
 +<doodle title="Make intersection types nullableauth="nicolasgrekas" voteType="single" closed="true"> 
 +   * Yes 
 +   * No 
 +</doodle> 
 + 
 +---- 
 + 
 +<doodle title="Preferred syntax" auth="nicolasgrekas" voteType="single" closed="true"> 
 +   "?" prefix 
 +   * "|null" suffix 
 +</doodle> 
 + 
 +---- 
 + 
 +<doodle title="Intersections should be" auth="nicolasgrekasvoteType="single" closed="true"> 
 +   * without brackets around 
 +   * with brackets around 
 +   allow both styles 
 +</doodle>
  
 ===== Patches and Tests ===== ===== Patches and Tests =====
rfc/nullable_intersection_types.1627032608.txt.gz · Last modified: 2021/07/23 09:30 by nicolasgrekas