Skip to content

Instantly share code, notes, and snippets.

@tom--
Last active April 14, 2016 15:05
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tom--/e95a10fbe4d34f8a72c9 to your computer and use it in GitHub Desktop.
Save tom--/e95a10fbe4d34f8a72c9 to your computer and use it in GitHub Desktop.
Something|null return type declaration

Table of Contents

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

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 {...}

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 singual 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:

<?php class Something { public static findSomething(Criteria $criteria) { // Search persistent data for Something matching $criteria if (/* no match found */) { return null; } // return a matching Something } }

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 Nullable 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:

<?php function foo(integer $i): Something|null { return $i < 0 ? null : (new Something()); }

(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 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 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.

@samdark
Copy link

samdark commented Dec 8, 2015

In Java everything's an object so it's always allowed to pass or return null instead of any object.

In TypeScript if null is allowed, type definition has ? at the end:

function (a: string?) { ... }

@nkostadinov
Copy link

In most languages you are allowed to return null and I think PHP should be no exception. If there is no result of the function why do we need to instantiate an object to return it ?

@mdomba
Copy link

mdomba commented Dec 8, 2015

there is already the idea to prefix with ? to declare nullable type, so in your case it would be ?Something

https://wiki.php.net/rfc/nullable_types

@samdark
Copy link

samdark commented Dec 8, 2015

I think postfix is a bit nicer.

@samdark
Copy link

samdark commented Dec 8, 2015

@mdomba, indeed. See discussion at php/php-src#1045

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment