Continued (hit send by hotkey accident): On Wed, Apr 13, 2016 at 10:50 AM, Levi Morrison <le...@php.net> wrote: > First, some background: several versions of PHP ago authors of > functions and methods could only restrict types to the array type or a > class/interface type. We slowly added some other types such as > callable and primitive types. These tools have been invaluable to > those who care about restricting the types of their inputs and > outputs. This type information reduces the code each author has to > write if they want to restrict to working with certain types and it > also provides a form of documentation. Overall these features have > been well received and are considered a good thing to do. > > However, as we have added these new restrictions we still cannot > express exactly what types are permitted in some common cases. > > 1. Return types cannot specify the function will return only type T or Null. > 2. Parameter types cannot express that an iterable type is required. > It's common for functions to work a stream of data and it is > irrelevant if it is an array or a Traversable object. > 3. Parameter types cannot express that that the parameter must > implement two different interfaces. For example, requiring a parameter > to implement both Countable and Traversable cannot be done. > > There are some common work-arounds to these issues: > > - Omit the type information and rely on documentation. > - Check the parameter type inside the function (eg > `assert(is_array($x) || $x instanceof Traversable)`) > - Introduce a new type that embodies the restrictions. If this in an > interface it must be implemented by every object you hope to use the > restriction with. > > In some cases these work-arounds are tolerable. However, some of them > are really painful. > > - Requiring a new supertype is intrusive. Code cannot always be > changed to use the new supertype. For example: > - Upstream projects that would not benefit from your changes. > - Primitives cannot be extended except by altering the engine. > In these cases a new type has to be introduced that proxies > behavior to the underlying object/primitive. > - Relying on documentation can lead to subtle and hard to diagnose > issues when it is used incorrectly. Erroring immediately is sometimes > preferable. > > All of these issues I've outlined can be nicely resolved by adding two > new kinds of types to our system: union and intersection types. A > union type requires the variable to match at least one of the types. > An intersection type requires the variable to match all of the types. > The vertical par symbol (OR) is used for unions and ampersand (AND) is > used for intersections. For example: > > function (A | B $var); would require $var to be either type A or type B. > function (A & B $var); would require $var to be type A and type B. > > To accommodate the common use-case of returning some type or Null we > would need to formally allow `Null` as an explicit type: > > function (): T | Null; > > Since this is a common use case some languages have a short-hand > notation to represent a union with Null:
function (): ?T; Examples of such languages include Swift, C#, OCaml and Hack (though the symbol is sometimes in the front and sometimes in the back. Later today I will be submitting RFCs for each of these proposals. Although they can work independently it is helpful to understand the overall goal and how they fit together, which has been the purpose of this email. Feedback for each RFC will belong in the thread for that piece, but discussion about the ideas overall is better suited here. -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php