====== PHP RFC: Nullable Return Type Declaration ======
* Version: 0.1
* Date: Apr 14 2016
* Author: Tom Worster, fsb@thefsb.org
* Status: Under Discussion
* First Published at: https://wiki.php.net/rfc/nullable_return
===== Introduction =====
Functions that return //Something or null// are highly conventional in PHP software and libraries. PHP 7.0 return type declaration does not accommodate it. We believe this would be a valuable addition to PHP 7.1 while, at the same time, we think it's too soon to loosen PHP's brand new type features with Nullable Type declaration for function arguments or Union Types.
===== Relation to existing work =====
[[https://wiki.php.net/rfc/union_types|Union Types]] (v0.2 Feb 2015, Levi Morrison) proposes to allow function arguments and returns to be declared as any number of possible types, for example
function f(Foo|Bar|Baz $x): Blub|Bla|BlaBla {...}
[[https://wiki.php.net/rfc/nullable_types|Nullable Types]] (v0.2 Apr 2014, Levi Morrison) proposes a special subset of Union Types in which arguments and returns can be declared as //Something or null//. The Nullable Types RFC also proposes a shorthand grammar using ''%%?%%'' while we use ''%%|null%%'' in order to be explicit. For example
function f(Foo|null $x): Blub|null {...}
===== Proposal =====
In this Nullable Return Type Declaration RFC we propose a special subset of the Nullable Types RFC proposal in which only the function return may be declared as nullable.
function f(): Blub|null {...}
PHP 7.0 already allows //limited// Nullable Type arguments via ''%%null%%'' default, e.g. ''%%function f(Foo $x = null) {}%%'' and we propose no change to that.
===== Note to the reader =====
The following arguments are based on opinion, experience and conversations. I tried to emphasize this by using first person singular when arguing my opinions and first person plural when referring to experience and opinion shared with my colleages. "We" specifically is not the journalistic "we" that refers to broader populations—it literally mean me and others I know and work with.
===== Arguments pro Nullable Returns =====
We have used object type hints for some time in PHP 5 and found the discipline they bring seems to improve code quality. Type hints help us think more carefully while programming. In code review and debugging they make it easier to understand the programmer's intent. So, in the expectation we'll make similar but even bigger profits with PHP 7's scalar type hints, return type declaration and strict types, we explored these features first.
Pretty much the first thing we noticed was that the //return Something or null// convention is incompatible with PHP 7.0 return type declarations.
In the //return Something or null// convention, the called method returns ''%%null%%'' when it cannot return a ''%%Something%%'' as requested but there's nothing unusual or unexpected about this outcome, i.e. the ''%%null%%'' does not signify an error. For example:
It turns out this is a very common scenario and the return Something or null convention is widespread not just in our own code but in the PHP libraries we use.
As a workaround, can we find a way to represent that a returned instance of ''%%Something%%'' is in fact void of ''%%Something%%''? The design would preferably be good enough to replace the current convention. Good enough must therefore involve being simple, obvious, and unambiguous, i.e. you couldn't possibly confuse a void ''%%Something%%'' with a real one. We haven't been able to devise anything remotely good enough.
In PHP 7.0 we found no better alternative for such methods than to omit a return declaration, which is rather sad.
===== Arguments pro Nullable Types and Union Types =====
Please refer to [[https://wiki.php.net/rfc/nullable_types|Nullable Types]], [[https://wiki.php.net/rfc/union_types|Union Types]].
===== Arguments contra Union Types =====
Unlike //something or null// returns, we haven't found a pressing need for Union Types in our work.
Unlike //something or null// returns, we generally don't have much difficulty finding workarounds. In fact, workaround isn't a good word for it because the reworked design that gets rid of Union function inputs and outputs often improves the code.
We want to use PHP strict type to enforce a discipline. API designs that allow a variety of types in a parameter, or that return a variety of types, are harder to understand for both the user and the implementer. The odds of making a mistake when handling Union Type inputs and outputs are worse than when the type is guaranteed to be //foo//. I prefer to seek an alternative design, even if it means rethinking part of the architecture. And in the unhappy case when we decide that Union is the least bad alternative, it seems fair to not declare return type at all and describe our failure in comments (with an apology).
PHP is "a pragmatic web-focused language" that "caters to the skill-levels of a wide range of users." A Union Types new feature in PHP risks being interpreted as an encouragement to use it. I think this unwise—Union Types surely have their place but I believe they are also hazardous and programmers do well to avoid needing them. The quality of open source PHP libs could suffer if Union Types is advertised as a fine new addition to PHP.
Finally, now seems not the right time for Union Types in the arc of PHP's history. PHP neophytes learn early about its type juggling, how useful it is and, hopefully, also that it is hazardous. After many years we now have a new way to declare type in PHP with an option to be strict about it. This allows a //radical tightening// of the use of type in our programs. It seems to me that 7.1 is too soon for the //radical loosening// that Union Types represents.
So, while I see __immediate need__ for //Something or null// returns, I don't believe generalizing this is warranted and could even turn out to be undesirable. Thus, according to my already mentioned gradualist preference, I think the PHP community should take time to use PHP 7's new type features before deciding that they should be dramatically loosened.
===== Arguments contra nullable argument type declarations =====
The arguments //contra// Union Types basically apply here too except that nullable argument declarations is a //less// radical loosening of PHP 7.0's new type declarations.
Unlike //something or null// returns, we haven't found a pressing need for nullable argument declarations. Existing PHP features, including a type with ''%%null%%'' default, has been sufficient for our needs. There has usually been a reasonable workaround in the design of the method signature. Indeed, sometimes the redesigned signature is better, suggesting that the discipline enforced by the current language limitations is worthwhile.
===== Proposal specifics =====
I propose PHP 7.1 introduce a grammar feature with which a function declares that it returns either a specified type or ''%%null%%''. For example:
(I’m open to other grammars but I like this because of the correspondence with the familiar ''%%@return%%'' docblock style.)
Any function that is allowed to declare a return type may declare that it can also return ''%%null%%''.
As in [[https://wiki.php.net/rfc/nullable_types|Nullable Types]], the null marker can be removed by a subclass but it cannot be added.
===== Proposed PHP Version(s) =====
7.1.
===== RFC Impact =====
The proposal maintains backward compatibility, has no effect on SAPIs, and does not include new constants or php.ini configurations.
===== Future Scope =====
In due course, experience with PHP 7's new type hint and declaration features may show that the benefits of generalization to Nullable Type and potentially to Union Types outweigh the hazards. The author is not in favor of doing this soon.
===== Proposed Voting Choices =====
We propose this RFC for discussion as an option among others:
- Nullable return (this RFC)
- [[https://wiki.php.net/rfc/nullable_types|Nullable Types]]
- [[https://wiki.php.net/rfc/union_types|Union Types]]
- none of the above
We propose to see what transpires in the discussion period before proposing voting choices.
===== Implementation =====
I don't have the skills to do this myself. I failed to adapt [[Dmitry's patch for Nullable Types|https://github.com/php/php-src/pull/1045]] although this may be a viable staring point. And I haven't yet found a volunteer to help.