Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:92263 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 37012 invoked from network); 13 Apr 2016 20:12:10 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 13 Apr 2016 20:12:10 -0000 X-Host-Fingerprint: 140.146.203.130 unknown Date: Wed, 13 Apr 2016 16:12:10 -0400 Received: from [140.146.203.130] ([140.146.203.130:12299] helo=localhost.localdomain) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id EE/C7-26321-918AE075 for ; Wed, 13 Apr 2016 16:12:10 -0400 Message-ID: To: internals@lists.php.net References: User-Agent: Pan/0.139 (Sexual Chocolate; GIT bf56508 git://git.gnome.org/pan2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Posted-By: 140.146.203.130 Subject: Re: Improving PHP's type system From: me@stephencoakley.com (Stephen Coakley) On Wed, 13 Apr 2016 10:53:13 -0600, Levi Morrison wrote: > Continued (hit send by hotkey accident): > > On Wed, Apr 13, 2016 at 10:50 AM, Levi Morrison 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. COOLNESS!! +10 I really like this mindset of a general solution to these stricter types. I think it will present a more consistent "interface" for using types across PHP in the future. In general, this is a more general and elegant solution to nullable type in properties, hints, and return types. I am eager to see what you have in those RFCs. ? -- Stephen