rfc:returntypehinting

This is an old revision of the document!


PHP RFC: Return Type-hinting

Introduction

Many developers would like to be able to declare the type of a return value. The basic idea has been proposed in at least three RFCs and has had a few other discussions (see references).

Return type-hinting has several motivators and use-cases:

  • Preventing unintended return types
  • Enforcing return types on interface implementations1).
  • Documenting return type information that is not easily invalidated (unlike comments).

Proposal

This proposal adds an optional return type-hint to all types of function declarations including closures, functions, interface method declarations and class declarations.

Example of function_declaration_stmt:

"function" ["&"] T_STRING "(" parameter_list ")" [":"  (T_STRING | array | callable)] "{"
    inner_statement_list
"}"

Variance and Signature Validation

The enforcement of the type-hint during inheritance will be covariant. Covariant return types is considered to be type sound and is used in many other languages2). The covariance allows an overrider to declare a return type that is a subclass of the original return type; this is illustrated in the examples below.

If a mismatch is detected during compile time (eg a class improperly overriding a return type) then E_COMPILE_ERROR will be issued. If a type mismatch is detected when the function returns then E_RECOVERABLE_ERROR will be issued.

Position of Type-hint

The two major conventions in other programming languages for placing return type information are:

  • Before the function name: <return_type> name(){}
  • After the parameter list: name() <return_type> {}

The former position has been proposed in the past and the RFCs were either declined or withdrawn. One cited issue is that many developers wanted to preserve the ability to search for function foo to be able to find the definition for foo.

The latter position is used in some functional languages; Facebook's Hack language also declared their return types here. Declaring the return type after the parameter list will have no conflicts in the parser.

Examples

Here are some examples of valid and invalid uses.

Examples of Valid Use

// Covariant return-type:
 
interface Collection {
    function map(callable $fn): Collection;
}
 
interface Set extends Collection {
    function map(callable $fn): Set;
}
// Overriding a method that did not have a return type:
 
interface Iterator {
    function rewind();
    function valid();
    function key();
    function current();
    function next();
}
 
class CommentsIterator implements Iterator {
    function current() : Comment;
}

Examples of Invalid Use

// return type does not match type-hint
function get_config(): array {
    return null;
}
// invalid type-hint
function answer(): int {
    return 42;
}
// Missing return type on override:
 
interface UserGateway {
    function find($id) : User; 
}
 
class UserGateway_MySql implements UserGateway {
    function find($id); // must return User or subtype of User
}
// Defining a return type on a Generator
function filter(Traversable $in, callable $filter): array {
    foreach ($in as $key => $value) {
        yield $filter($key, $value);
    }
}

Multiple Return Types

This proposal specifically does not allow multiple return type-hints; if such a feature is needed then use PHP's existing dynamic nature and leave off the return type.

Differences from Past RFCs

This proposal differs from past RFCs in several key ways:

  • We keep the current type-hint options. Past proposals have suggested new types such as void, int, string or scalar.
  • We allow type-hints on all function types3). Will Fitch's proposal suggested adding it for methods only.
  • We keep the current search patterns. You can still search for function foo to find foo's definition; all previous RFCs broke this.
  • We do not modify or add keywords. Past RFCs have proposed new keywords such as nullable and more. We still require the function keyword.

Open Issues

Allowing NULL for Objects

Consider the following function:

function foo() : DateTime { 
    return null; 
}

It declares that it will return DateTime but returns null. In type-hints for parameters this would fail unless = null was appended to the end. It is a common pattern to return null to indicate that there is no result for something that normally returns an object.

We can introduce some syntax to allow null to be passed.

One proposal is to use |

function foo() : DateTime|null { 
    return null; 
}

I personally feel that this gives the impression that we allow multiple return types. This proposal explicitly does not allow multiple return types.

Another option is to use Hack's syntax:

function foo() : ?DateTime { 
    return null; 
}

Another option is to use a C# inspired syntax:

function foo() : DateTime? { 
    return null; 
}

We could choose to delay this decision to a later date; not allowing null would be future-compatible with such a decision.

Generators

According to Nikita Popov, generators have a concept of a return value that may be exposed at some future point. His recommendation is to not allow return types on generators as they may conflict with future work in this area. If type-hinting on generators were to work the same way it does on other functions then the only valid return type would be Generator; therefore not allowing return types on generators is not a loss at all.

Other Impact

On Backward Compatiblity

This RFC is backwards compatible with previous PHP releases.

On SAPIs

There is no impact on any SAPI.

On Existing Extensions

There is no known impact on extensions.

On Performance

Until a patch is completed (Joe Watkins has offered to provide one) the impact on performance is unknown.

Proposed PHP Version(s)

As there are no known BC breaks this RFC targets PHP 5.7. If a BC break is discovered it will be proposed for PHP 6.0.

Proposed Voting Choices

This RFC modifies the PHP language syntax and therefore requires a two-third majority of votes.

Patches and Tests

Currently there isn't a patch; Joe Watkins has offered to provide one.

References

Future Work

  • Reflection support
  • Consider allowing extensions to define type-hints for return values.
1)
See Variance and Signature Validation and examples for more details on how this works
2)
C++, Java and others use covariant return types, just as is proposed here.
3)
Except generators
rfc/returntypehinting.1396460616.txt.gz · Last modified: 2017/09/22 13:28 (external edit)