Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:92252 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 11399 invoked from network); 13 Apr 2016 16:50:59 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 13 Apr 2016 16:50:59 -0000 Authentication-Results: pb1.pair.com smtp.mail=morrison.levi@gmail.com; spf=pass; sender-id=pass Authentication-Results: pb1.pair.com header.from=morrison.levi@gmail.com; sender-id=pass Received-SPF: pass (pb1.pair.com: domain gmail.com designates 209.85.192.182 as permitted sender) X-PHP-List-Original-Sender: morrison.levi@gmail.com X-Host-Fingerprint: 209.85.192.182 mail-pf0-f182.google.com Received: from [209.85.192.182] ([209.85.192.182:33662] helo=mail-pf0-f182.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 59/D2-26321-0F87E075 for ; Wed, 13 Apr 2016 12:50:58 -0400 Received: by mail-pf0-f182.google.com with SMTP id 184so36853036pff.0 for ; Wed, 13 Apr 2016 09:50:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:sender:date:message-id:subject:from:to; bh=9epulea5f+uSBKAbti6EmzEJ8s+i7gB+y4PV3egUg5I=; b=c471B522/11ror7pPnM2E8QRy8+zp/9CRUuHeNnPirsxvLy/zsi/E7WriCi12SnQ1y NWiFWF1nism/Fuay7oxsfvc3xjZvatg4h6fcdYQp+pqfg1Kqn3Ti2+N0S7RwDid9xtrY tF7rPKhOau1A6uJitxQlv6BmGRToDKYjyQZT1aK40gcIpTofAIqFk6sx9jbUFzy6aB8t ih7uHgxU+HIlnlqO9mraZ3jlE6h89ZArZ7f4+Hyb1FoMmH3qAQEfJkrG0/T9P1LruXxJ JwRvTRgM+RcnPIGgN6ajZjoxuYr+1PUEGUE88dqnqOP+dBtRYUj0Bf0ei7Ljm069qFbq JxGQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:sender:date:message-id:subject:from :to; bh=9epulea5f+uSBKAbti6EmzEJ8s+i7gB+y4PV3egUg5I=; b=ArMGCjudoSzg2mhzSBwrgufnjQiIxuxRwgXx2osdD9yQGJyXzMzikr6ZxB47CWvX8k mVibtvuvfxjjVl52beh6vQEoL/jzargkkfd75xa1Ddd92m503T+SPwTNCCNzefhThuMu LTSkEI+8ZbV90KS3fwuPhy32DZaeCfMyJKAHEhCj5AkKUm83i/mYkR0aNWPjBMGNS5Nv bm3aj3mBoZcjw2jc9NXRVOC1I/NctA6WikvGIjvN/SSmaTncpoCLekiqc73xX0P/FCAL W/ueKm1P6Y3DyAnQoSs82r0UAPf3VvUR8ntZtkS9gVW+upnU++b79I1RyXMs58lEwcby dOFw== X-Gm-Message-State: AOPr4FVb7iJuLlrnQWGaTaYIQ4/1clTkIfNKnQtgFivGViX8KvC9uPZ4kwSowaKIV9tZ2gEskLJL2smiq8zsyQ== MIME-Version: 1.0 X-Received: by 10.98.67.139 with SMTP id l11mr14294138pfi.112.1460566254041; Wed, 13 Apr 2016 09:50:54 -0700 (PDT) Sender: morrison.levi@gmail.com Received: by 10.66.163.232 with HTTP; Wed, 13 Apr 2016 09:50:53 -0700 (PDT) Date: Wed, 13 Apr 2016 10:50:53 -0600 X-Google-Sender-Auth: JLD2Jk7BzAmYZA2yxPomjRHqeBA Message-ID: To: internals Content-Type: text/plain; charset=UTF-8 Subject: Improving PHP's type system From: levim@php.net (Levi Morrison) 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: